加载自定义yml配置文件
Spring Boot 加载自定义 YML 配置文件:从原理到实战
Spring Boot 默认支持 application.yml 配置文件的加载,但在需要拆分配置(如将业务配置与系统配置分离)时,我们常需加载自定义 YML 文件(如 custom.yml)。与 properties 文件不同,自定义 YML 文件无法直接通过 @PropertySource 加载(默认不支持 YML 解析),需通过自定义 PropertySourceFactory 实现。从 “原理分析→实现步骤→实战示例→注意事项” 四个维度,详细讲解自定义 YML 配置的加载方法。
核心问题:为何自定义 YML 无法直接加载?
Spring Boot 的 @PropertySource 注解默认仅支持 properties 格式 的配置文件(通过 DefaultPropertySourceFactory 解析),而 YML 文件采用缩进式语法,需要专用的解析器(如 YamlPropertiesFactoryBean)。
- properties 文件:键值对格式(
key=value),可直接被@PropertySource解析; - YML 文件:层级结构(
key: value),需先转换为键值对格式(如parent.child=value)才能被 Spring 识别。
因此,加载自定义 YML 文件的核心是:实现一个能将 YML 转换为键值对的 PropertySourceFactory。
解决方案:自定义 YML 解析工厂(PropertySourceFactory)
通过自定义 PropertySourceFactory,利用 Spring 内置的 YamlPropertiesFactoryBean 解析 YML 文件,将其转换为 Properties 对象(键值对格式),供 @PropertySource 使用。
1. 实现 YmlPropertySourceFactory
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.springframework.lang.Nullable;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.util.StringUtils;
import java.io.IOException;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 自定义 YML 配置文件解析工厂,支持 @PropertySource 加载 YML 文件
*/
public class YmlPropertySourceFactory implements PropertySourceFactory {
private static final Logger log = LoggerFactory.getLogger(YmlPropertySourceFactory.class);
public PropertySource<?> createPropertySource(
String name, // 配置源名称(可为 null,自动生成)
EncodedResource resource // 资源对象(包含 YML 文件信息)
) throws IOException {
// 1. 将 YML 文件解析为 Properties 对象(键值对格式)
Properties propertiesFromYaml = loadYamlIntoProperties(resource);
// 2. 处理解析结果(若解析失败,使用默认资源加载方式)
if (propertiesFromYaml == null) {
return (name != null)
? new PropertiesPropertySource(name, resource.getResource())
: new PropertiesPropertySource(resource.getResource().getFilename(), resource.getResource());
}
// 3. 生成配置源名称(优先使用传入的 name,否则使用文件名)
String sourceName = name;
if (!StringUtils.hasText(sourceName)) {
sourceName = resource.getResource().getFilename();
}
if (sourceName == null) {
log.error("无法获取配置文件名称: {}", resource);
throw new RuntimeException("加载 YML 配置文件失败:" + resource);
}
// 4. 返回 Properties 格式的配置源
return new PropertiesPropertySource(sourceName, propertiesFromYaml);
}
/**
* 将 YML 资源解析为 Properties 对象
*/
private Properties loadYamlIntoProperties(EncodedResource resource) {
try {
// 使用 Spring 内置的 YamlPropertiesFactoryBean 解析 YML
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(resource.getResource()); // 设置 YML 资源
factory.afterPropertiesSet(); // 初始化解析器
return factory.getObject(); // 获取解析后的 Properties
} catch (IllegalStateException e) {
log.error("解析 YML 文件失败: {}", resource.getResource().getFilename(), e);
return null;
}
}
}
核心逻辑:
- 利用
YamlPropertiesFactoryBean将 YML 层级结构转换为Properties键值对(如custom.name=张三); - 兼容解析失败的场景,降级为默认资源加载方式;
- 自动生成配置源名称,确保 Spring 能正确识别配置来源。
2. 使用自定义 YML 配置
(1)创建自定义 YML 文件(src/main/resources/custom.yml)
# 自定义 YML 配置示例
custom:
name: "订单服务"
type-fields: # 映射为 Map<String, String>
key1: "value1"
key2: "value2"
db: # 嵌套结构(需在配置类中定义对应字段)
url: "jdbc:mysql://localhost:3306/custom_db"
username: "root"
(2)定义配置类,绑定 YML 配置
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import lombok.Data;
import java.util.Map;
/**
* 自定义 YML 配置绑定类
*/
// Lombok 注解,自动生成 getter/setter
// 注册为 Spring Bean
// 绑定前缀为 "custom" 的配置
public class CustomProperties {
private String name; // 对应 custom.name
private Map<String, String> typeFields; // 对应 custom.type-fields(YML 中横杠自动映射驼峰)
private DbConfig db; // 对应 custom.db(嵌套结构)
// 嵌套配置类(对应 custom.db)
public static class DbConfig {
private String url;
private String username;
}
}
关键注解说明:
@PropertySource:指定自定义 YML 文件路径,并通过factory指定解析工厂;@ConfigurationProperties(prefix = "custom"):将前缀为custom的配置绑定到当前类字段;- 字段名映射规则:YML 中的
type-fields自动映射到驼峰命名的typeFields。
(3)使用配置类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
public class CustomConfigController {
private CustomProperties customProperties; // 注入配置类
public CustomProperties getCustomConfig() {
return customProperties;
// 输出结果:
// {
// "name": "订单服务",
// "typeFields": {"key1":"value1", "key2":"value2"},
// "db": {"url":"jdbc:mysql://localhost:3306/custom_db", "username":"root"}
// }
}
}
进阶场景:多环境与多文件加载
1. 多环境自定义配置(如 custom-dev.yml、custom-prod.yml)
(1)创建多环境 YML 文件
src/main/resources/
├── custom-dev.yml # 开发环境配置
├── custom-prod.yml # 生产环境配置
└── custom.yml # 通用配置(多环境共享)
(2)根据激活的环境加载对应文件
通过 @PropertySource 的 value 属性支持 SpEL 表达式,动态加载环境相关的配置:
public class CustomProperties {
// ... 字段定义
}
- 若激活
dev环境(spring.profiles.active=dev),则加载custom-dev.yml; - 若未指定环境,默认加载
custom-default.yml(需提前创建)。
2. 加载多个自定义 YML 文件
通过 @PropertySource 的 value 数组指定多个文件,优先级按顺序递增(后加载的覆盖先加载的):
public class CustomProperties {
// ... 字段定义
}
注意事项与常见问题
1. 字段映射失败(如 YML 有值但配置类字段为 null)
问题原因:
- 字段名与 YML 配置不匹配(未遵循驼峰映射规则,如 YML 是
type-fields,类字段应为typeFields); - 未添加
@Component或@Configuration注解,配置类未被 Spring 扫描; - 未生成 getter/setter 方法(Lombok 的
@Data注解可自动生成,若手动编写需确保方法存在)。
解决方案:
- 严格遵循 “YML 横杠命名→类驼峰命名” 的映射规则;
- 确保配置类被 Spring 扫描(添加
@Component或在配置类上标注@Configuration); - 检查 getter/setter 是否存在(可通过 IDE 生成或使用 Lombok 注解)。
2. 配置文件路径错误(FileNotFoundException)
问题原因:
@PropertySource的value路径错误(如拼写错误、文件不在classpath下);- 多模块项目中,配置文件放置位置错误(需放在主模块的
src/main/resources下)。
解决方案:
- 检查路径是否正确(如
classpath:custom.yml表示文件在src/main/resources根目录); - 多模块项目中,确保配置文件位于 启动类所在模块 的
resources目录。
3. 配置覆盖顺序
Spring Boot 配置加载存在优先级,自定义 YML 可能被其他配置覆盖,优先级从高到低为:
- 命令行参数(如
java -jar app.jar --custom.name=test); - 系统环境变量;
application-{profile}.yml(环境特定配置);application.yml(全局配置);- 自定义 YML 文件(如
custom.yml); - 类路径下的
default.properties。
注意:若需自定义 YML 优先级高于 application.yml,可通过 @Order 注解调整,但不推荐(易导致配置混乱)。
4. 支持 YAML 列表(List)配置
YML 支持列表结构,配置类中可用 List 接收:
(1)YML 配置:
custom:
servers:
- "192.168.1.100"
- "192.168.1.101"
- "192.168.1.102"
(2)配置类字段:
public class CustomProperties {
private List<String> servers; // 接收列表配置
}
总结
加载自定义 YML 配置文件的核心是通过 YmlPropertySourceFactory 解析 YML 为键值对格式,关键步骤可概括为:
- 实现解析工厂:自定义
YmlPropertySourceFactory,利用YamlPropertiesFactoryBean解析 YML; - 创建配置文件:在
resources目录下创建自定义 YML(如custom.yml); - 绑定配置类:通过
@PropertySource(factory=...)和@ConfigurationProperties绑定配置; - 注入使用:将配置类注入到业务组件,直接使用绑定的字段