Home > Back-end >  How does Spring pick the property value to use if a property is defined in multiple property files?
How does Spring pick the property value to use if a property is defined in multiple property files?

Time:12-28

If a property is defined in multiple property files how does Spring decide what the value of the variable should be?

My guess

My belief based on running some code is that the result is indeterministic. If multiple property files define the same property name, then it's seemingly random as to which property file will be used.

How Spring Implements this (my guess)

Spring keeps a list of PropertySources and when a property value is needed it walks the PropertySources one by one until it finds the value of a property.

This is based on some testing I did and this answer: From https://stackoverflow.com/a/74934269/3281336 which says:

If you want to get a property, the get method of the MutablePropertySources is called which iterates over all PropertySources until it finds that property.

Since by default, you don't know what order the list will be in, therefore, you don't know what value you'll get (when a property is defined in multiple property files).

How I proved this to myself

To prove to myself how this works, I created two property files and defined the same property name foo.baz. See below:

// File: src/main/resources/file1.properties
foo.baz=Defined in file1.properties

// File: src/main/resources/file2.properties
foo.baz=Defined in file2.properties

Next, I created a @Configuration class MyConfig which reads the two property files file1.properties and file2.properties.

@PropertySource("classpath:datasource.properties")
@PropertySource("classpath:file1.properties")
@PropertySource("classpath:file2.properties")
@Configuration
public class MyConfig{

This class has a bean which will get created when the app starts up, and it will print the value that Spring selected for the property foo.baz. The code is:

    @Bean
    public Object whichProp(@Value("${foo.bar}") String fooBar, @Value("${foo.baz}") String fooBaz){
        System.out.println("Looks like foo.bar prop is set to "   fooBar    ", foo.baz="   fooBaz);
        return new Object();
    }

The result I got was:

Looks like foo.bar prop is set to defined in application.properties, foo.baz=Defined in file2.properties

I also wrote a @Bean to dump/display the Spring Properties List (based on this answer).

    @Bean
    public Object DisplayPropertiesEnvironment(Environment environment) {
        AbstractEnvironment env = (AbstractEnvironment) environment;
        for (org.springframework.core.env.PropertySource<?> source : env.getPropertySources()) {
            if (source instanceof MapPropertySource) {
                MapPropertySource mapPropertySource = (MapPropertySource) source;
                System.out.println("Prop: "   source.getName()   "="   mapPropertySource.getSource());
            }
        }
        return new Object();
    }

In conclusion

I've shared my belief and given the reasons. Please let me know the answer. Also if there is a URL to the Spring documentation that explains how works please share it.

CodePudding user response:

You can refer this Spring boot documentation to know all the possible ways and order to load property. In your case if you use multiple @PropertySource as mentioned in document

In cases where a given property key exists in more than one .properties file, the last @PropertySource annotation processed will 'win' and override any previous key with the same name.

CodePudding user response:

Spring will always read the files in the order they were listed. This is because of the nature of @Repeatable annotations, and Spring doesn't mess with this. I.e., multiple of the same annotation is really a repeatable annotation. In this case, PropertySources.

So, in your example, values in file1.properties will override datasource.properties and values in file2.properties will override both datasource.properties and file1.properties.

  • Related