Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot and multiple external configuration files

People also ask

Can we have multiple configuration files in spring boot?

To add different files you can use the spring. config. location properties which takes a comma separated list of property files or file location (directories). The one above will add a directory which will be consulted for application.

Can you have multiple configuration files in spring for one project?

Yes, in large projects, having multiple Spring configurations increase maintainability and modularity. You can also upload one XML file that will contain all configs.

How do I load multiple configuration files in spring?

You may load multiple Spring bean configuration files in the code : ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"Spring-Common. xml", "Spring-Connection. xml","Spring-ModuleA.

How do you externalize configuration using spring boot?

Spring Boot lets you externalize your configuration so that you can work with the same application code in different environments. You can use properties files, YAML files, environment variables, and command-line arguments to externalize configuration.


UPDATE: As the behaviour of spring.config.location now overrides the default instead of adding to it. You need to use spring.config.additional-location to keep the defaults. This is a change in behaviour from 1.x to 2.x


When using Spring Boot the properties are loaded in the following order (see Externalized Configuration in the Spring Boot reference guide).

  1. Command line arguments.
  2. Java System properties (System.getProperties()).
  3. OS environment variables.
  4. JNDI attributes from java:comp/env
  5. A RandomValuePropertySource that only has properties in random.*.
  6. Application properties outside of your packaged jar (application.properties including YAML and profile variants).
  7. Application properties packaged inside your jar (application.properties including YAML and profile variants).
  8. @PropertySource annotations on your @Configuration classes.
  9. Default properties (specified using SpringApplication.setDefaultProperties).

When resolving properties (i.e. @Value("${myprop}") resolving is done in the reverse order (so starting with 9).

To add different files you can use the spring.config.location properties which takes a comma separated list of property files or file location (directories).

-Dspring.config.location=your/config/dir/

The one above will add a directory which will be consulted for application.properties files.

-Dspring.config.location=classpath:job1.properties,classpath:job2.properties

This will add the 2 properties file to the files that are loaded.

The default configuration files and locations are loaded before the additonally specified spring.config.location ones meaning that the latter will always override properties set in the earlier ones. (See also this section of the Spring Boot Reference Guide).

If spring.config.location contains directories (as opposed to files) they should end in / (and will be appended with the names generated from spring.config.name before being loaded). The default search path classpath:,classpath:/config,file:,file:config/ is always used, irrespective of the value of spring.config.location. In that way you can set up default values for your application in application.properties (or whatever other basename you choose with spring.config.name) and override it at runtime with a different file, keeping the defaults.


With Spring boot , the spring.config.location does work,just provide comma separated properties files.

see the below code

@PropertySource(ignoreResourceNotFound=true,value="classpath:jdbc-${spring.profiles.active}.properties")
public class DBConfig{

     @Value("${jdbc.host}")
        private String jdbcHostName;
     }
}

one can put the default version of jdbc.properties inside application. The external versions can be set lie this.

java -jar target/myapp.jar --spring.config.location=classpath:file:///C:/Apps/springtest/jdbc.properties,classpath:file:///C:/Apps/springtest/jdbc-dev.properties

Based on profile value set using spring.profiles.active property, the value of jdbc.host will be picked up. So when (on windows)

set spring.profiles.active=dev

jdbc.host will take value from jdbc-dev.properties.

for

set spring.profiles.active=default

jdbc.host will take value from jdbc.properties.


Spring boot 1.X and Spring Boot 2.X don't provide the same options and behavior about the Externalized Configuration.

The very good answer of M. Deinum refers to Spring Boot 1 specifities.
I will update for Spring Boot 2 here.

Environment properties sources and order

Spring Boot 2 uses a very particular PropertySource order that is designed to allow sensible overriding of values. Properties are considered in the following order:

  • Devtools global settings properties on your home directory (~/.spring-boot-devtools.properties when devtools is active).

  • @TestPropertySource annotations on your tests.

  • @SpringBootTest#properties annotation attribute on your tests. Command line arguments.

  • Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property).

  • ServletConfig init parameters.

  • ServletContext init parameters.

  • JNDI attributes from java:comp/env.

  • Java System properties (System.getProperties()).

  • OS environment variables.

  • A RandomValuePropertySource that has properties only in random.*.

  • Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants).

  • Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants).

  • Application properties outside of your packaged jar (application.properties and YAML variants).

  • Application properties packaged inside your jar (application.properties and YAML variants).

  • @PropertySource annotations on your @Configuration classes. Default properties (specified by setting SpringApplication.setDefaultProperties).

To specify external properties files these options should interest you :

  • Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants).

  • Application properties outside of your packaged jar (application.properties and YAML variants).

  • @PropertySource annotations on your @Configuration classes. Default properties (specified by setting SpringApplication.setDefaultProperties).

You can use only one of these 3 options or combine them according to your requirements.
For example for very simple cases using only profile-specific properties is enough but in other cases you may want to use both profile-specific properties, default properties and @PropertySource.

Default locations for application.properties files

About application.properties files (and variant), by default Spring loads them and add their properties in the environment from these in the following order :

  • A /config subdirectory of the current directory

  • The current directory

  • A classpath /config package

  • The classpath root

The higher priorities are so literally :
classpath:/,classpath:/config/,file:./,file:./config/.

How to use properties files with specific names ?

The default locations are not always enough : the default locations like the default filename (application.properties) may not suit. Besides, as in the OP question you may need to specify multiple configuration files other than application.properties (and variant).
So spring.config.name will not be enough.

In this case you should provide an explicit location by using the spring.config.location environment property (which is a comma-separated list of directory locations or file paths).
To be free about the filenames pattern favor the list of file paths over the list of directories.
For example do like that :

java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties

That way is the most verbose that just specifying the folder but it is also the way to specify very finely our configuration files and to document clearly the properties effectively used.

spring.config.location now replaces default locations instead of adding to them

With Spring Boot 1, the spring.config.location argument adds specified locations in the Spring environment.
But from Spring Boot 2, spring.config.location replaces the default locations used by Spring by the specified locations in the Spring environment as stated in the documentation.

When custom config locations are configured by using spring.config.location, they replace the default locations. For example, if spring.config.location is configured with the value classpath:/custom-config/,file:./custom-config/, the search order becomes the following:

  1. file:./custom-config/

  2. classpath:custom-config/

spring.config.location is now a way to make sure that any application.properties file has to be explicitly specified.
For uber JARs that are not supposed to package application.properties files, that is rather nice.

To keep the old behavior of spring.config.location while using Spring Boot 2 you can use the new spring.config.additional-location property instead of spring.config.location that still adds the locations as stated by the documentation :

Alternatively, when custom config locations are configured by using spring.config.additional-location, they are used in addition to the default locations.


In practice

So supposing that as in the OP question, you have 2 external properties file to specify and 1 properties file included in the uber jar.

To use only configuration files you specified :

-Dspring.config.location=classpath:/job1.properties,classpath:/job2.properties,classpath:/applications.properties   

To add configuration files to these in the default locations :

-Dspring.config.additional-location=classpath:/job1.properties,classpath:/job2.properties

classpath:/applications.properties is in the last example not required as the default locations have that and that default locations are here not overwritten but extended.


Take a look at the PropertyPlaceholderConfigurer, I find it clearer to use than annotation.

e.g.

@Configuration
public class PropertiesConfiguration {


    @Bean
    public PropertyPlaceholderConfigurer properties() {
        final PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
//        ppc.setIgnoreUnresolvablePlaceholders(true);
        ppc.setIgnoreResourceNotFound(true);

        final List<Resource> resourceLst = new ArrayList<Resource>();

        resourceLst.add(new ClassPathResource("myapp_base.properties"));
        resourceLst.add(new FileSystemResource("/etc/myapp/overriding.propertie"));
        resourceLst.add(new ClassPathResource("myapp_test.properties"));
        resourceLst.add(new ClassPathResource("myapp_developer_overrides.properties")); // for Developer debugging.

        ppc.setLocations(resourceLst.toArray(new Resource[]{}));

        return ppc;
    }