3

I am trying to reload configuration of my application during runtime. The configuration is in a yaml file and the binding with @ConfigurationProperties works as expected. Next thing is. I want to reload the config when the yaml has changed. Or rather I am checking with @Scheduled whether the file has changed.

I would like to avoid running a second server for having my Environment update. The two questions I have:

  1. How do I update the environment, ConfigurableEnvironment maybe?
  2. How do I propagate these?

Spring cloud config documentation states:

The EnvironmentChangeEvent covers a large class of refresh use cases, as long as you can actually make a change to the Environment and publish the event (those APIs are public and part of core Spring)

So publishing the Event is working, but I do not get on how to actually update the properties.

2
  • Make a POST to /refresh on your Spring Boot server. You can include this when the event is published Commented May 16, 2018 at 6:56
  • Both these solutions include running cloud config server. This is not feasible for me. Commented May 16, 2018 at 7:07

1 Answer 1

4

There is quite a discussion on that: how to refresh properties without any configuration server. There is a Dave Syer post on that here which brings some light - but still isn't self-explanatory.

The most natural approach for spring-boot/-cloud would be following (as discussed on spring-cloud-config github):

@Component @ConfigurationProperties("ignored") @RefreshScope public class Config { private List<String> path; public List<String> getPath() { return path; } public void setPath(List<String> path) { this.path = path; } } 

This doesn't work due to some proxy issues between @RefreshScope and @ConfigurationProperties - both annotations result in bean proxies with are at odds with each other.

Therefore I started looking at it from a spring perspective. The propertySources are accessible through Environment so you can access and modify them by

final String propertySourceName = "externalConfiguration"; // name of propertySource as defined by // @PropertySource(name = "externalConfiguration", value = "${application.config.location}") ResourcePropertySource propertySource = new ResourcePropertySource(propertySourceName, new FileSystemResource(file)); MutablePropertySources sources = ctx.getEnvironment().getPropertySources(); sources.replace(propertySourceName, propertySource); 

My use case was based on "user editing the file" so the properties refreshed was based on the FileSystemWatcher, which mutated the propertySources. For the sources to be correctly ingested by the configuration bean, the scope of the bean needed to be a prototype - to be correctly rebuilt on every invocation.

The complete example is available as a gist. No config server is included whatsoever. Hope that helps

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Jakub, this was quite helpful
@HknLof thanks for this. What's the best way to refresh those beans that need to re-read a config object like your ExternalConfiguration? Should I use the listener pattern (ie, all interested beans subscribe to ExternalConfiguration, which becomes a listener too), or does Spring have some support for it?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.