Spring Boot ConfigurationProperties tutorial
Novice programmers rarely see the value in externalized configuration. It's tedious and doesn't result in an immediate payoff. That means this task is often overlooked or done poorly, if at all.
For those who create applications and microservices with Spring Boot, however, the availability of configuration annotations and the application.properties file simplifies data externalization. With Spring Boot configuration tools, externalization is largely straightforward, which means that novice developers no longer have any excuses to eschew the responsibility of configuration-based best practices from the get-go.
Spring Boot @ConfigurationProperties example
To demonstrate how Spring Boot configuration works, we'll start with the creation of a Spring Starter Project with the Spring Tool Suite.
The sample project settings are as follows:
- GroupId: com.mcnz.spring.configuration.example.
- ArtifactId: spring-configuration-example.
- Version: 1.0-SNAPSHOT.
- Name: Spring Configuration Tutorial.
Spring Boot's properties and YAML files
Spring Boot projects store their configuration data in a properties file. By convention, this Spring configuration file is placed in the resources folder of the project and named application.properties.
Optionally, a YAML-based Spring properties file is acceptable as well.
Spring's application.properties file
To demonstrate how the application.properties Spring configuration file works with the Spring @ConfigurationProperties annotation, we fill the file with a variety of data types:
- Basic String data.
- A list of values.
- A data map.
- An inner class with properties.
The Spring Boot application.properties file with our added data looks as follows.
#Spring Boot configuration file example
# simple spring configurationd data
spring.boot.config.example.company = "Dreamix"
spring.boot.config.example.suite = 1113
spring.boot.config.example.active = true
# list data in spring configuration file
spring.boot.config.example.list[0] = "list-data-0"
spring.boot.config.example.list[1] = "list-data-1"
# simple map in a spring configuration file
spring.boot.config.example.map.key1="value1"
spring.boot.config.example.map.key2="value2"
# inner class in Spring config file
spring.boot.config.example.innerClass.property1 = "annotations"
spring.boot.config.example.innerClass.property2 = "xml"
spring.boot.config.example.innerClass.property3 = "YAML"
Spring Boot's @ConfigurationProperties annotation
The next step is to create a class that will be decorated with the Spring Boot @ConfigurationProperties and Spring @Component annotations. This class injects the properties defined in the properties file into instance variables at runtime.
We call the class that bears the Spring @ConfigurationProperties annotation SpringBootConfiguration.
package com.mcnz.spring.configuration;
import org.springframework.boot.context.properties.*;
import org.springframework.stereotype.*;
@ConfigurationProperties(prefix="spring.boot.config.example")
@Component
public class SpringBootConfiguration {
}
The prefix argument shows which properties, starting with this prefix, are to be used by the class decorated with the @ConfigurationProperties annotation.
Field injection with Spring's @ConfigurationProperties
Now it's time for the cool part.
To access the basic String properties defined in the Spring Boot configuration file, all you need to do is add a property with the name that matches one in the application.properties file, along with the corresponding setters and getters. The SpringBootConfiguration example class looks like this:
package com.mcnz.spring.configuration;
import org.springframework.boot.context.properties.*;
import org.springframework.stereotype.*;
@ConfigurationProperties(prefix="spring.boot.config.example")
@Component
public class SpringBootConfiguration {
private String company;
private int suite;
private boolean active;
public String getCompany() { return company; }
public void setCompany(String c) { company = c; }
public int getSuite() { return suite; }
public void setSuite(int s) { suite = s; }
public boolean isActive() { return active; }
public void setActive(boolean a) { this.active = a; }
}
All we need to do to quickly test this in the @SpringBootApplication annotated class is as follows:
- Implement the CommandLineRunner interface.
- Override the run() method.
- Autowire the SpringBootConfiguration bean into the class.
It looks as shown in Figure 3.
As we expect, when the class runs, here is the output.
"Dreamix"
1113
true
Spring ConfigurationProperties with Lists and Maps
We can also convert the Map and List data defined in the Spring configuration file into Java objects. To do this, declare instances of the appropriate type in the code.
private Map<String, String> map;
private List<String> list;
public Map<String, String> getMap() {return map;}
public void setMap(Map<String, String> m) {map = m;}
public List<String> getList() {return list;}
public void setList(List<String> l) {list = l;}
A user can also declare an inner class within the configuration class, annotate it with @ConfigurationProperties and point the prefix attribute to the root name of the properties to be used. The Spring Boot configuration takes care of the rest.
@ConfigurationProperties(prefix="spring.boot.config.example")
@Component
public class SpringBootConfiguration {
private final InnerClass innerClass = new InnerClass();
public InnerClass getInnerClass() {
return innerClass;
}
@ConfigurationProperties(prefix="innerClass")
public class InnerClass {
private String property1;
private String property2;
private String property3;
public String getProperty1() {return property1;}
public void setProperty1(String p) { property1 = p; }
public String getProperty2() {return property2;}
public void setProperty2(String p) { property2 = p; }
public String getProperty3() {return property3;}
public void setProperty3(String p) { property3 = p; }
}
/* Previously coded properties getters and setters omitted */
}
When saved, the List, Map and InnerClass are all easily accessed anywhere the SpringConfigurationExampleApplication class is autowired.
Here is the complete SpringConfigurationExampleApplication with the configuration class autowired in.
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringConfigurationExampleApplication implements CommandLineRunner {
@Autowired
SpringBootConfiguration config;
public static void main(String[] args) {
SpringApplication.run(SpringConfigurationExampleApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
System.out.println(config.getCompany());
System.out.println(config.getSuite());
System.out.println(config.isActive());
System.out.println(config.getList().get(0));
System.out.println(config.getMap());
System.out.println(config.getInnerClass().getProperty1());
}
}
When the Spring configuration test class runs, the final output is observed.
Benefits of Spring's ConfigurationProperties
As an application matures and is regularly updated, we need a way to easily change the configurations that doesn't require hours to determine which property we changed and hunt for it in the code. Other benefits of an externalized configuration include the following:
- Better organization of the project.
- Better reliability.
- Reduced costs and risks.
- Easy refactoring.
- Flexibility when testing.
Spring Boot's ability to externalize configuration makes it easy to define data in simple property files and subsequently access that data anywhere that the Spring Boot configuration class is autowired into your application.
The source code for this application is available on GitHub.
Editor's note: This article was originally published in July 2019 and has been updated for clarity and to improve reader experience.
Cameron McKenzie has been a Java EE software engineer for 20 years. His current specialties include Agile development; DevOps; Spring; and container-based technologies such as Docker, Swarm and Kubernetes.