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+ 提供了突破口:@PropertySourcefactory 属性允许我们指定一个自定义的 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


原始标题:@PropertySource with YAML Files in Spring Boot | Baeldung