A Magic Around Spring Boot Externalized Configuration
There are some things I really like in Spring Boot, and one of them is an externalized 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 locations: classpath:/,classpath:/config/,file:./,file:./config/
. Of course, we may override it. You can change the name of the 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 contain 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.
File global.yml
property1: global
property2: global
property3: global
File override.yml
property2: override
property3: override
File app.yml
.
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 makes sense if we want to override settings defined inside application.yml
. Let’s consider the following configuration files available on classpath.
File application.yml
.
property1: app
property2: app
File sample-appconfig.yml
.
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 files. 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.
File application.yml
.
property1: app
property2: app
File application-override.yml
.
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, an 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 to load an additional property source only for a 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.
File application.yml
.
property1: app
property2: app
File additional.yml
.
property1: additional
property2: additional
property3: additional
property4: additional
File additional-test.yml
.
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 have been injected into the application using @Value
annotation. Spring Boot provides 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 a 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 a 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 a 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.
6 COMMENTS