2

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.

PatS
  • 8,833
  • 12
  • 57
  • 100

3 Answers3

2

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.

Oliver
  • 1,465
  • 4
  • 17
  • This appears to be the case. I swapped the declaration of `file1.properties` and `file2.properties`, and the one listed last was used. What was interesting, however, was that if I **also** defined `foo.baz` in `src/main/resources/application.properties`, then **application.properties** won. So based on my testing the order is: (1) cmd line wins, (2) ENV is next, (3) application.properties next, (4) remainder of properties files with subsequent property files being able to override values defined in earlier files. – PatS Dec 28 '22 at 20:10
  • Great! Feel free to check if you think this is the best answer. – Oliver Dec 29 '22 at 02:29
2

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.

Saurabh
  • 882
  • 1
  • 5
  • 16
1

Spring allows you to define property values in multiple property files and then specify the property files to be loaded via the spring.config.name property. By default, Spring will look for property files with the names application.properties and application.yml.

If you have defined a property in multiple property files, then Spring will use the value of the property in the property file that was loaded last. This means that property values defined in property files that are loaded later will overwrite property values defined in property files that are loaded earlier.

For example, if you have defined the property my.property in both application.properties and application-prod.properties, and you have specified spring.config.name=prod to load the application-prod.properties file, then Spring will use the value of my.property as defined in application-prod.properties.

You can also use the spring.config.additional-location property to specify additional directories or files to search for property files. Property values defined in property files in these locations will be loaded after the property files specified by the spring.config.name property.