A Magic Around Spring Boot Externalized Configuration

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

spring-config-1

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.

spring-config-2

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.

spring-config-3

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.

spring-config-4

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.

spring-config-5

You want to try it by yourself? The source code with examples is available on GitHub in repository springboot-configuration-playground.

6 COMMENTS

comments user
Amadeo

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.

    comments user
    Piotr Mińkowski

    Hi. Well I think you may change the logging level for the whole whole org.springframework

comments user
smlee729

I think in additional test, `property1` should be also `additional`. Isn’t it?

comments user
Aniyah Berger

I am really happy to say it’s an interesting post to read . I learn new information from your article , you are doing a great job . Keep it up

    comments user
    piotr.minkowski

    Thanks 🙂

Leave a Reply