There are some things I really like in Spring Boot, and one of them is an externalized (external) configuration. Spring Boot allows you to configure your application in many ways. You have 17 levels of loading configuration properties into application. All of them are described in the 24th Chapter of Spring Boot documentation available here.
This article was inspired by some last talks with developers about problems with the configuration of their applications. They haven’t heard about some interesting features that may be used to make it more flexible and clear.
By default Spring Boot tries to load application.properties
(or application.yml
) from the following paths: classpath:/,classpath:/config/,file:./,file:./config/
. Of course, we may override it. You can change the name of main configuration file by setting environment property spring.config.name
or just change the whole searching path by setting property spring.config.location
. It can contains names of directories, as well as file paths.
Let’s consider the following situation. We want to define different levels of configuration, where for example global properties applying to all our applications are overridden by specific settings defined only for a single application. We have three configuration sources.
property1: global property2: global property3: global
property2: override property3: override
property3: app
The result is visible on the test below. It is important to properly set an order of property sources, where the most significant source is placed in the end:
classpath:/global.yml,classpath:/override.yml,classpath:/app.yml
The configuration visible above replaces all the default location used by Spring Boot. It doesn’t even try to locate application.properties
(or application.yml
), but only the files listed inside spring.config.location
environment variable. If we would like to add some custom config locations to the default location we may use spring.config.additional-location
variable. However, this only make sense if we want to override settings defined inside application.yml
. Let’s consider the following configuration files available on classpath.
property1: app property2: app
property2: sample property3: sample
In that test case we are using spring.config.additional-location
environment variable to include sample-appconfig.yml
file to the default config locations. It overrides property2
, and adds new property property3
.
It is possible to create profile-specific application properties file. It has to be defined following naming convention: application-{profile}.properties
(or application-{profile}.yml
). If standard application.properties
or application-default.properties
are available under default config locations, Spring Boot still loads, but with lower priority than profile-specific file.
Let’s consider the following configuration files available on the classpath.
property1: app property2: app
property2: override property3: override
The following test activates Spring Boot profile override and checks if the right order of loading default and profile-specific application properties.
Additional property sources may also be included by the application through @PropertySource
annotation on the @Configuration
class. By default, application failed to start if such a file is not found. Fortunately, we can change this behaviour by setting property ignoreResourceNotFound
to true
.
@SpringBootApplication @PropertySource(value = "classpath:/additional.yml", ignoreResourceNotFound = true) public class ConfigApp { public static void main(String[] args) { SpringApplication.run(ConfigApp.class, args); } }
The properties loaded through @PropertySource
annotation have really low priority (16 for available 17 levels). They can be overridden by default application properties. We can also define @TestPropertySource
on our JUnit test with to load additional property source only for particular test. Such a property file will override both properties defined inside default application properties file and file included with @PropertySource
.
Let’s consider the following configuration files available on the classpath.
property1: app property2: app
property1: additional property2: additional property3: additional property4: additional
property2: additional-test property3: additional-test
The following test illustrates loading order when both @PropertySource
and @TestPropertySource
are used inside the source code.
All the properties visible above has been injected into the application using @Value
annotation. Spring Boot provides the another way to inject configuration properties into classes – via @ConfigurationProperties
. Generally @ConfigurationProperties
allows you to inject more complex structures into the application. Let’s imagine we need to inject list of objects. Each object contains some fields. Here’s our sample object class definition.
public class Person { private String firstName; private String lastName; private int age; // getters and setters }
The class containing list of Person
objects should be annotated with @ConfigurationProperties
. The value inside annotation persons-list
has to be the same as a prefix of property defined inside application.yml
file.
@Component @ConfigurationProperties("persons-list") public class PersonsList { private List<Person> persons = new ArrayList<>(); public List<Person> getPersons() { return persons; } public void setPersons(List<Person> persons) { this.persons = persons; } }
Here’s list of persons defined inside application.yml
.
persons-list.persons: - firstName: John lastName: Smith age: 30 - firstName: Tom lastName: Walker age: 40 - firstName: Kate lastName: Hamilton age: 50
The following test injects PersonsList
bean containing list of persons and checks if they match the list defined inside application.yml
.
You want to try it by yourself? The source code with examples is available on GitHub in repository springboot-configuration-playground.
Hi, i’m having some problems with property loading and need to know the properties that were processed, the path and the order. Something like tracing the property loading. Do you know if the exists a flag to show this?
Something similar to:
file application.properties loaded from somejar.jar:/application.properties
file application.properties loaded from somepath:/application.properties
Thanks.
LikeLike
Hi. Well I think you may change the logging level for the whole whole org.springframework
LikeLike
I think in additional test, `property1` should be also `additional`. Isn’t it?
LikeLike
No 🙂 Look here: https://docs.spring.io/spring-boot/docs/2.1.8.RELEASE/reference/html/boot-features-external-config.html.
LikeLike