1. Overview
A common practice in Spring Boot is using an external configuration to define our properties. This allows us to use the same application code in different environments.
We can use properties files, YAML files, environment variables and command-line arguments.
In this short tutorial, we’ll explore the main differences between properties and YAML files.
2. Properties Configuration
By default, Spring Boot can access configurations set in an application.properties file, which uses a key-value format:
spring.datasource.url=jdbc:h2:dev
spring.datasource.username=SA
spring.datasource.password=password
Here each line is a single configuration, so we need to express hierarchical data by using the same prefixes for our keys. And in this example, every key belongs to spring.datasource.
2.1. Placeholders in Properties
Within our values, we can use placeholders with the ${} syntax to refer to the contents of other keys, system properties, or environment variables:
app.name=MyApp
app.description=${app.name} is a Spring Boot application
2.2. List Structure
If we have the same kind of properties with different values, we can represent the list structure with array indices:
application.servers[0].ip=127.0.0.1
application.servers[0].path=/path1
application.servers[1].ip=127.0.0.2
application.servers[1].path=/path2
application.servers[2].ip=127.0.0.3
application.servers[2].path=/path3
2.3. Multiple Profiles
Since version 2.4.0, Spring Boot supports creating multi-document properties files. Simply put, we can split a single physical file into multiple logical documents.
This allows us to define a document for each profile we need to declare, all in the same file:
logging.file.name=myapplication.log
bael.property=defaultValue
#---
spring.config.activate.on-profile=dev
spring.datasource.password=password
spring.datasource.url=jdbc:h2:dev
spring.datasource.username=SA
bael.property=devValue
#---
spring.config.activate.on-profile=prod
spring.datasource.password=password
spring.datasource.url=jdbc:h2:prod
spring.datasource.username=prodUser
bael.property=prodValue
Note we use the ‘#---’ notation to indicate where we want to split the document.
In this example, we have two spring sections with different profiles tagged. Also, we can have a common set of properties at the root level — in this case, the logging.file.name property will be the same in all profiles.
2.4. Profiles Across Multiple Files
As an alternative to having different profiles in the same file, we can store multiple profiles across different files. Prior to version 2.4.0, this was the only method available for properties files.
We achieve this by putting the name of the profile in the file name — for example, application-dev.yml or application-dev.properties.
3. YAML Configuration
3.1. YAML Format
As well as Java properties files, we can also use YAML-based configuration files in our Spring Boot application. YAML is a convenient format for specifying hierarchical configuration data.
Now let’s take the same example from our properties file and convert it to YAML:
spring:
datasource:
password: password
url: jdbc:h2:dev
username: SA
This can be more readable than its property file alternative since it does not contain repeated prefixes.
3.2. List Structure
YAML has a more concise format for expressing lists:
application:
servers:
- ip: '127.0.0.1'
path: '/path1'
- ip: '127.0.0.2'
path: '/path2'
- ip: '127.0.0.3'
path: '/path3'
3.3. Multiple Profiles
Unlike properties files, YAML supports multi-document files by design, and this way, we can store multiple profiles in the same file no matter which version of Spring Boot we use.
In this case, however, the spec indicates we have to use three dashes to indicate the start of a new document:
logging:
file:
name: myapplication.log
---
spring:
config:
activate:
on-profile: staging
datasource:
password: 'password'
url: jdbc:h2:staging
username: SA
bael:
property: stagingValue
Note: We usually don’t want to include both the standard application.properties and the application.yml files in our project at the same time, as it could lead to unexpected results.
For instance, if we combine the properties shown above (in an application.yml file) with the properties described in Section 2.3., then bael.property would be assigned with defaultValue instead of with the profile-specific value. This is simply because the application.properties are loaded later on, overriding the values assigned up to that point.
4. Spring Boot Usage
Now that we’ve defined our configurations, let’s see how to access them.
4.1. Value Annotation
We can inject the values of our properties using the @Value annotation:
@Value("${key.something}")
private String injectedProperty;
Here the property key.something is injected via field injection into one of our objects.
4.2. Environment Abstraction
We can also obtain the value of a property using the Environment API:
@Autowired
private Environment env;
public String getSomeKey(){
return env.getProperty("key.something");
}
4.3. ConfigurationProperties Annotation
Finally, we can also use the @ConfigurationProperties annotation to bind our properties to type-safe structured objects:
@ConfigurationProperties(prefix = "mail")
public class ConfigProperties {
String name;
String description;
...
5. Conclusion
In this article, we’ve seen some differences between properties and yml Spring Boot configuration files. We also saw how their values could refer to other properties. Finally, we looked at how to inject the values into our runtime.
As always, all the code examples are available over on GitHub.