1. 概述
本文将演示如何在 Spring Boot 中通过 @PropertySource
注解加载 YAML 格式的配置文件。
虽然 Spring Boot 原生支持多种外部化配置方式,但 ❌ @PropertySource
默认并不支持 YAML 文件。这是官方明确指出的限制,尤其在 Spring Framework 的文档中有说明。
这意味着,如果你想直接用 @PropertySource
引入 YAML,会发现它“不工作”——这是一个常见的“踩坑点”。不过别急,我们可以通过自定义扩展来补全这个功能✅。
2. @PropertySource 与 YAML 的兼容性问题
Spring Boot 对 .properties
和 .yml
都有良好支持,但两者的加载机制不同:
- 使用
application.yml
启动时,Spring Boot 自动通过YamlPropertySourceLoader
加载。 - 而
@PropertySource
注解默认只识别.properties
文件,底层使用的是PropertiesPropertySourceLoader
。
⚠️ 所以,以下写法不会生效:
@PropertySource("classpath:config.yml") // ❌ 不会解析 YAML 内容
但好在 Spring 4.3+ 提供了突破口:@PropertySource
的 factory
属性允许我们指定一个自定义的 PropertySourceFactory
,从而接管资源解析逻辑。
3. 自定义 YamlPropertySourceFactory
解决思路很简单:写一个工厂类,把 YAML 文件转成 Spring 能识别的 PropertySource
。
public class YamlPropertySourceFactory implements PropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource)
throws IOException {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(encodedResource.getResource());
Properties properties = factory.getObject();
return new PropertiesPropertySource(encodedResource.getResource().getFilename(), properties);
}
}
关键点解析:
- ✅
YamlPropertiesFactoryBean
:Spring 内置工具类,可将 YAML 文件解析为标准的java.util.Properties
对象。 - ✅
PropertiesPropertySource
:Spring 环境中可用的属性源包装类,支持层级结构扁平化(如yaml.name
)。 - ✅ 整个过程简单粗暴,只需实现一个方法即可。
📌 注意:该工厂会将 YAML 的嵌套结构自动展平为 key.value
形式的字符串键,这与 Spring 的常规处理方式一致。
4. 实际使用示例
4.1 准备 YAML 文件
创建 foo.yml
:
yaml:
name: foo
aliases:
- abc
- xyz
4.2 定义配置类
使用 @ConfigurationProperties
绑定属性,并通过 factory
指定自定义工厂:
@Configuration
@ConfigurationProperties(prefix = "yaml")
@PropertySource(value = "classpath:foo.yml", factory = YamlPropertySourceFactory.class)
public class YamlFooProperties {
private String name;
private List<String> aliases;
// getter 和 setter 省略
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getAliases() {
return aliases;
}
public void setAliases(List<String> aliases) {
this.aliases = aliases;
}
}
4.3 编写集成测试验证
@RunWith(SpringRunner.class)
@SpringBootTest
public class YamlFooPropertiesIntegrationTest {
@Autowired
private YamlFooProperties yamlFooProperties;
@Test
public void whenFactoryProvidedThenYamlPropertiesInjected() {
assertThat(yamlFooProperties.getName()).isEqualTo("foo");
assertThat(yamlFooProperties.getAliases()).containsExactly("abc", "xyz");
}
}
✅ 测试通过,说明 YAML 属性已成功注入。
5. 总结
- ❌
@PropertySource
默认不支持 YAML 是 Spring 的一个“历史遗留”限制。 - ✅ 利用
factory
属性 + 自定义PropertySourceFactory
,可以轻松突破此限制。 - ✅ 核心在于
YamlPropertiesFactoryBean
的使用,它是 Spring 提供的现成工具。 - ✅ 适用于需要加载非标准命名 YAML 文件(如
custom-config.yml
)的场景,而不是依赖application.yml
。
所有示例代码已托管至 GitHub:https://github.com/example/spring-boot-properties-demo