Spring-cloud-config: Spring Cloud Refresh event does not recognize removed properties?

Created on 16 Aug 2016  路  6Comments  路  Source: spring-cloud/spring-cloud-config

See http://stackoverflow.com/questions/38932168/spring-cloud-refresh-event-does-not-recognize-removed-properties please

Overview

I have a Spring Boot 1.4/1.5 application running with Spring Cloud. My app is using the native profile to pull settings from an external config.properties file. The config server is embedded inside the same application.

In the config.properties file I have added the following setting:

app.setting=helloworld

What works:

When I change the property and send a REFRESH event, relevant beans marked are reloaded and the change is recognized correctly.

What doesn't work:

If I actually remove the property from config.properties, (by commenting it out for instance), the REFRESH event does nothing to actually refresh the application. Spring Cloud seems to not recognize the fact that the property is removed and when the data-binder proceeds to update the state of the world it misses the fact that the property is removed, and the corresponding bean linked to it must also be refreshed and its field set to blank/null, etc.

It looks like the data-binder only looks at what is at the moment available in the configuration and does not keep record of what was vs what is.

The only way to actually disable that setting in the bean configuration state is not by removing it, but by actually setting it to a blank value (which is a new value, given the setting is just a String). Note the field in Java bean mapped to this property has no default value other than null, and the value is not defined anywhere else (as in an embedded application.properties file, etc)

What might I be missing?

question

Most helpful comment

I've run into a similar issue when refreshing an external config.properties file. The issue manifested itself with my config.properties because it only had a single entry in it.

To demonstrate:

Start by overriding the application properties

application.properties

some.value=abc

config.properties

some.value=xyz

Initially, using some.value will render "xyz"

To show that the value can be updated, change the value in the config.properties

config.properties

some.value=123

Using the /refresh endpoint, refresh the context and then using some.value will render "123"

Now, by removing the property, then we can see the value does not get updated

config.properties

// now empty

Using the /refresh endpoint, refresh the context and then using some.value will still render "123". It hadn't recognised that the field had been removed, nor used the "abc" value from the application.properties.

The issue stems from the class ConfigFileApplicationListener which on line 428, identifies the properties file as empty, so doesn't load the file into the property sources that are later used to compare the new properties to the old in the ContextRefresher class. The scenario appears to keep the old one in memory.

To workaround this issue, when you only have a single property, you could add property like a.b which would force the file to be loaded with the no value and result in the correct functionality.

config.properties

a.b=true
// item removed, but use some property to make sure it's read later

Hope this helps

All 6 comments

You are not missing anything. Binding only affects fields that actually have a value in the configuration. You need to work with that constraint really.

That's fine. Thanks for the confirmation. I am assuming there is no easy way to bypass the constraint or at least have it be some sort of a configuration knob?

Not that I am aware of.

Got it. Thanks again

I've run into a similar issue when refreshing an external config.properties file. The issue manifested itself with my config.properties because it only had a single entry in it.

To demonstrate:

Start by overriding the application properties

application.properties

some.value=abc

config.properties

some.value=xyz

Initially, using some.value will render "xyz"

To show that the value can be updated, change the value in the config.properties

config.properties

some.value=123

Using the /refresh endpoint, refresh the context and then using some.value will render "123"

Now, by removing the property, then we can see the value does not get updated

config.properties

// now empty

Using the /refresh endpoint, refresh the context and then using some.value will still render "123". It hadn't recognised that the field had been removed, nor used the "abc" value from the application.properties.

The issue stems from the class ConfigFileApplicationListener which on line 428, identifies the properties file as empty, so doesn't load the file into the property sources that are later used to compare the new properties to the old in the ContextRefresher class. The scenario appears to keep the old one in memory.

To workaround this issue, when you only have a single property, you could add property like a.b which would force the file to be loaded with the no value and result in the correct functionality.

config.properties

a.b=true
// item removed, but use some property to make sure it's read later

Hope this helps

Thanks very much for sharing.

Was this page helpful?
0 / 5 - 0 ratings