Loading Multiple YAML Configuration Files in Spring Boot
In a Spring Boot application, configuration management plays a crucial role in adapting the application to different environments, such as development, testing, and production. YAML (YAML Ain't Markup Language) is a human - readable data serialization format commonly used in Spring Boot for configuration files. While Spring Boot automatically loads application.yml and environment - specific files like application - dev.yml, there are scenarios where you may need to load multiple custom YAML configuration files. This blog will provide a detailed guide on how to load multiple YAML configuration files in a Spring Boot application.
Table of Contents#
- Why Load Multiple YAML Configuration Files?
- Prerequisites
- Basic Setup of a Spring Boot Project
- Loading Multiple YAML Files Using
@PropertySource - Loading Multiple YAML Files Using
YamlPropertySourceLoader - Common Practices and Best Practices
- Example Usage
- Conclusion
- References
1. Why Load Multiple YAML Configuration Files?#
- Separation of Concerns: You can separate different types of configurations into different files. For example, you can have one file for database configurations and another for security - related settings.
- Environment - Specific Configurations: In addition to the standard
application - {env}.ymlfiles, you may have custom configurations that vary based on different environments. - Modularity: It allows for better modularity in your application. If you are working on a large - scale project, different modules can have their own configuration files.
2. Prerequisites#
- Java Development Kit (JDK) 8 or higher
- Apache Maven or Gradle for dependency management
- Spring Boot Starter Parent in your project
3. Basic Setup of a Spring Boot Project#
You can create a Spring Boot project using Spring Initializr (https://start.spring.io/). Select the necessary dependencies such as Spring Web if you are building a web application.
Maven Example#
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.4</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>Gradle Example#
plugins {
id 'org.springframework.boot' version '2.5.4'
id 'io.spring.dependency - management' version '1.0.11.RELEASE'
}
dependencies {
implementation 'org.springframework.boot:spring - boot - starter - web'
}4. Loading Multiple YAML Files Using @PropertySource#
The @PropertySource annotation is used to load properties from external files. By default, it does not support YAML files, but we can create a custom property source factory to make it work.
Custom Property Source Factory#
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import org.yaml.snakeyaml.Yaml;
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
public class YamlPropertySourceFactory implements PropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
Properties propertiesFromYaml = loadYamlIntoProperties(resource);
String sourceName = name != null ? name : resource.getResource().getFilename();
return new PropertiesPropertySource(sourceName, propertiesFromYaml);
}
private Properties loadYamlIntoProperties(EncodedResource resource) throws IOException {
Yaml yaml = new Yaml();
Map<String, Object> yamlMap = yaml.load(resource.getInputStream());
Properties properties = new Properties();
if (yamlMap != null) {
flattenMap(yamlMap, properties, "");
}
return properties;
}
private void flattenMap(Map<String, Object> map, Properties properties, String parentKey) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = parentKey.isEmpty() ? entry.getKey() : parentKey + "." + entry.getKey();
if (entry.getValue() instanceof Map) {
flattenMap((Map<String, Object>) entry.getValue(), properties, key);
} else {
properties.put(key, entry.getValue());
}
}
}
}Loading YAML Files#
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.Configuration;
@Configuration
@PropertySource(value = {"classpath:custom - config.yml", "classpath:another - config.yml"}, factory = YamlPropertySourceFactory.class)
public class AppConfig {
// Configuration class
}5. Loading Multiple YAML Files Using YamlPropertySourceLoader#
The YamlPropertySourceLoader can also be used to load YAML files.
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.core.io.support.EncodedResource;
import java.io.IOException;
public class CustomYamlPropertySourceFactory extends DefaultPropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
if (resource == null) {
return super.createPropertySource(name, resource);
}
YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
return loader.load(name, resource.getResource()).get(0);
}
}And then use it in the configuration class:
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.Configuration;
@Configuration
@PropertySource(value = {"classpath:custom - config.yml", "classpath:another - config.yml"}, factory = CustomYamlPropertySourceFactory.class)
public class CustomAppConfig {
// Configuration class
}6. Common Practices and Best Practices#
- Naming Convention: Use a clear naming convention for your YAML files, such as
module - config.ymlor{env}-{module}-config.yml. - Error Handling: When loading multiple YAML files, handle potential errors such as file not found or invalid YAML syntax gracefully.
- Order of Loading: Be aware of the order in which you load the YAML files. Properties in later - loaded files may override properties in earlier - loaded files.
7. Example Usage#
Let's assume we have two YAML files:
custom - config.yml#
database:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: passwordanother - config.yml#
api:
base - url: https://example.com/api
timeout: 5000We can inject these properties into a service class:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class MyService {
@Value("${database.url}")
private String databaseUrl;
@Value("${api.base - url}")
private String apiBaseUrl;
public String getDatabaseUrl() {
return databaseUrl;
}
public String getApiBaseUrl() {
return apiBaseUrl;
}
}8. Conclusion#
Loading multiple YAML configuration files in a Spring Boot application provides more flexibility and better organization of your application's configurations. Whether you use @PropertySource with a custom property source factory or YamlPropertySourceLoader, you can easily manage different types of configurations in separate files.
9. References#
- Spring Boot Documentation: https://docs.spring.io/spring - boot/docs/current/reference/html/
- YAML Official Website: https://yaml.org/