Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best way to add a new property source in Spring?

I'd like to add a new property source that could be used to read property values in an application. I'd like to do this using Spring. I have a piece of code like this in a @Configuration class:

@Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {        
    PropertySourcesPlaceholderConfigurer properties = new PropertySourcesPlaceholderConfigurer();
    MutablePropertySources sources = new MutablePropertySources();
    MyCustomPropertySource propertySource = new MyCustomPropertySource("my custom property source");
    sources.addFirst(propertySource);
    properties.setPropertySources(sources);
    return properties;
}

This seems to work pretty well. However, what it is also doing is overriding other property values (e.g. server.port property in application.properties file used by spring boot) which I don't want to overwrite. So the basic question is what's the best way to add this propertysource but not have it override other properties. Any way to grab the existing propertysources and simply add on to it?

like image 905
Gevork Palyan Avatar asked Jan 08 '23 04:01

Gevork Palyan


2 Answers

I got this working by adding a custom initiailizer to my spring boot app:

@SpringBootApplication
public class MyApp {

    public static void main(String[] args) {
        new SpringApplicationBuilder(MyApp.class)
            .initializers(new MyContextInitializer())  // <---- here
            .run(args);
    }

}

Where MyContextInitializer contains: -

public class MyContextInitializer implements
    ApplicationContextInitializer<ConfigurableApplicationContext> {

    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        ConfigurableEnvironment environment = configurableApplicationContext.getEnvironment();

        // Create map for properites and add first (important)
        Map<String, Object> myProperties = new HashMap<>();
        myProperties.put("some-prop", "custom-value");
        environment.getPropertySources().addFirst(
            new MapPropertySource("my-props", myProperties));
    }

}

Note, if your application.yaml contains: -

some-prop: some-value
another-prop: this is ${some-prop} property

Then the initialize method will update the some-prop to custom-value and when the app loads it will have the following values at run-time:

some-prop: custom-value
another-prop: this is custom-value property

Note, if the initialize method did a simple System.setProperty call i.e.

    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        ConfigurableEnvironment environment = configurableApplicationContext.getEnvironment();
        System.setProperty("some-prop", "custom-value");
    }

... then the another-prop would be equal to this is some-value property which is not what we generally want (and we lose the power of Spring config property resolution).

like image 113
bobmarksie Avatar answered Jan 17 '23 18:01

bobmarksie


Try setting IgnoreUnresolvablePlaceholders to TRUE. I had a similar problem which I was able to resolve in this way. In my case, I had another placeholderconfigurer, which was working - but properties in the second one were not being resolved unless I set this property to TRUE.

@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {        
    PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
    propertySourcesPlaceholderConfigurer.setIgnoreUnresolvablePlaceholders(Boolean.TRUE);
    propertySourcesPlaceholderConfigurer.setIgnoreResourceNotFound(Boolean.TRUE);
    return propertySourcesPlaceholderConfigurer;
}
like image 28
Woodchuck Avatar answered Jan 17 '23 18:01

Woodchuck