25

At the project with Spring Boot we use application.properties but need to configure some of these properties (like port number of logging level) based on an external configuration. We access the configuration via API so it is known only at runtime.

Is there a way to override or set some Spring properties at runtime (for example using a bean) and if yes how can this be achieved?

ps-aux
  • 11,627
  • 25
  • 81
  • 128
  • I don't understand. You can use all sorts of different sources of data for your `Environment`. Did you read the docs: http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-external-config? Why does that not work? – Dave Syer Jan 13 '15 at 13:21
  • Port number and logging level will require a whole context restart, you may be better off restarting your whole app as well. Take a look at this answer https://stackoverflow.com/a/52648630/39998 – David Hofmann Oct 04 '18 at 14:33
  • There is a question regarding Spring Boot and Java EE hot-reloading properties here https://stackoverflow.com/a/52648630/39998 – David Hofmann Oct 04 '18 at 14:23

2 Answers2

21

You could do this with Spring Cloud Config

Just for the purpose of illustration, here's a relatively quick way to see dynamic property overrides at runtime:

First, for your bean to be able to pick up changed properties, you need to annotate it with

@RefreshScope

Add the spring cloud dependency to your spring boot app, eg for gradle

compile group: 'org.springframework.cloud', name: 'spring-cloud-starter', version: '1.1.1.RELEASE'

( NB You also need the spring boot actuator dependency.)

With the app running, you can view your current config at eg

http://localhost:8080/env

eg if you have a property 'my.property' in application.properties, you'll see something like:

"applicationConfig: [classpath:/application.properties]": {
  "my.property": "value1",
  etc

To change the value, POST my.property=value2 to /env as application/x-www-form-urlencoded

eg

curl -X POST http://localhost:8080 -d my.property=value2

GET /env again and you'll see the new value appears under the "manager" section

To apply the changed properties, do an empty POST to /refresh. Now your bean will have the new value.

Todderz
  • 321
  • 2
  • 6
4

Could you use system properties to pass in the variable? If you configure the PropertyPlaceholderConfigurer you can set the precedence of system properties vs file properties.

For example, something like:

@Bean public PropertyPlaceholderConfigurer placeHolderConfigurer() {
    PropertyPlaceholderConfigurer props = new PropertyPlaceholderConfigurer()
    props.setSystemPropertiesMode( PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_OVERRIDE )
    props.setLocations(new 
PathMatchingResourcePatternResolver().getResources("classpath:/**.properties"));
    props
}

The above would load your .properties file, but we set the priority to be system variables first, so if you set a system variable that will override the same variable in the config.

Alternatively, looking at the docs, Spring recommends defining a search order in your Environment:

[PropertyPlaceholderConfigurer is still appropriate for use when] existing configuration makes use of the "systemPropertiesMode" and/or "systemPropertiesModeName" properties. Users are encouraged to move away from using these settings, and rather configure property source search order through the container's Environment; however, exact preservation of functionality may be maintained by continuing to use PropertyPlaceholderConfigurer.

Hopefully one of the above should sort out what you need?

rhinds
  • 9,976
  • 13
  • 68
  • 111
  • 1
    I wouldn't recommend using a `PropertyPlaceholderConfigurer` in a Spring Boot app (it's already provided). – Dave Syer Jan 13 '15 at 13:20
  • `PropertyPlaceholderConfigurer ` is deprecated, alternative is `PropertySourcesPlaceholderConfigurer ` Here is java doc link --> https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.html – drt May 21 '21 at 16:00