1. 概述

本文将详细介绍 如何在 Spring Boot 中从 YAML 配置文件注入 Map 类型的属性

我们会先简单回顾 Spring 对 YAML 的支持机制,然后通过一个完整示例演示如何将 YAML 中的层级结构映射到 Java 中的 Map 字段。最后还会对比 @ConfigurationProperties@Value 的使用场景,帮你避开常见踩坑点。

2. Spring 框架中的 YAML 文件支持

YAML 是 Spring 开发者常用的外部化配置格式。✅ Spring 原生支持 YAML 作为 properties 的替代方案,并通过 SnakeYAML 库在底层完成解析

一个典型的 application.yml 文件长这样:

server:
  port: 8090
  application:
    name: myapplication
    url: http://myapplication.com

相比 .properties,YAML 层级清晰、可读性强,特别适合表达嵌套结构的配置。⚠️ 注意:虽然 Spring 默认加载 application.ymlapplication.properties,但如果你想加载自定义 YAML 文件,需要配合 @PropertySource 使用——不过它不支持直接加载 YAML,需额外配置 YamlPropertySourceFactory

3. 如何从 YAML 注入 Map

Spring Boot 提供了 @ConfigurationProperties 注解,可以将配置文件中的属性批量绑定到 Java Bean,非常适合处理复杂结构的数据,比如 Map、List 等。

示例配置

我们在 application.yml 中定义如下结构:

server:
  application:
    name: InjectMapFromYAML
    url: http://injectmapfromyaml.dev
    description: How To Inject a map from a YAML File in Spring Boot
  config:
    ips:
      - 10.10.10.10
      - 10.10.10.11
      - 10.10.10.12
      - 10.10.10.13
    filesystem:
      - /dev/root
      - /dev/md2
      - /dev/md4
  users: 
    root:
      username: root
      password: rootpass
    guest:
      username: guest
      password: guestpass

目标是:

  • applicationMap<String, String>
  • configMap<String, List<String>>
  • usersMap<String, Credential>,其中 Credential 是自定义类

创建配置类

@Component
@ConfigurationProperties(prefix = "server")
public class ServerProperties {

    private Map<String, String> application;
    private Map<String, List<String>> config;
    private Map<String, Credential> users;

    // 标准 getter 和 setter
    public Map<String, String> getApplication() {
        return application;
    }

    public void setApplication(Map<String, String> application) {
        this.application = application;
    }

    public Map<String, List<String>> getConfig() {
        return config;
    }

    public void setConfig(Map<String, List<String>> config) {
        this.config = config;
    }

    public Map<String, Credential> getUsers() {
        return users;
    }

    public void setUsers(Map<String, Credential> users) {
        this.users = users;
    }

    public static class Credential {
        private String username;
        private String password;

        // getter 和 setter
        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }
}

关键点:

  • 使用 @ConfigurationProperties(prefix = "server") 告诉 Spring 只绑定以 server. 开头的属性
  • 所有字段名需与 YAML 中的 key 保持一致(支持驼峰/下划线自动转换)
  • 内部类 Credential 必须是 static,否则无法正确绑定嵌套对象

⚠️ 踩坑提醒:Spring Boot 2.2+ 默认关闭松散绑定(relaxed binding),建议显式启用 @ConfigurationProperties 扫描。可在主类上添加:

@EnableConfigurationProperties(ServerProperties.class)

编写测试验证注入结果

@RunWith(SpringRunner.class)
@SpringBootTest
class MapFromYamlIntegrationTest {

    @Autowired
    private ServerProperties serverProperties;

    @Test
    public void whenYamlFileProvidedThenInjectSimpleMap() {
        assertThat(serverProperties.getApplication())
          .containsOnlyKeys("name", "url", "description");

        assertThat(serverProperties.getApplication()
          .get("name")).isEqualTo("InjectMapFromYAML");
    }

    @Test
    public void whenYamlFileProvidedThenInjectComplexMap() {
        assertThat(serverProperties.getConfig()).hasSize(2);

        assertThat(serverProperties.getConfig()
          .get("ips")
          .get(0)).isEqualTo("10.10.10.10");

        assertThat(serverProperties.getUsers()
          .get("root")
          .getUsername()).isEqualTo("root");
    }
}

测试通过,说明 Map 结构已正确注入 ✅

4. @ConfigurationProperties vs @Value

这两个注解都能读取配置,但定位完全不同,别乱用 ❌

对比项 @ConfigurationProperties @Value
绑定方式 批量绑定整个对象结构 单个属性注入
类型支持 复杂类型(Map、List、嵌套类) 基本类型 + SpEL
松散绑定 支持(如 contextPathcontext-path 不支持
元数据生成 ✅ 自动生成 IDE 提示 ❌ 无
推荐场景 配置中心化、结构化管理 临时取值、条件判断

📌 简单粗暴总结

  • 你要读一堆相关配置?用 @ConfigurationProperties
  • 你只想取一个值做判断?用 @Value

Spring 官方也建议优先使用 @ConfigurationProperties 来组织配置,更安全、更易维护。

5. 总结

本文演示了如何利用 @ConfigurationProperties 将 YAML 文件中的嵌套结构映射为 Java 中的 Map 类型,涵盖:

  • 简单 Map(String → String)
  • 复合结构(String → List)
  • 自定义对象作为 value

同时强调了与 @Value 的本质区别,避免误用。这种集中式配置管理方式在微服务中非常实用,建议集合备用。

示例代码已托管至 GitHub:https://github.com/baeldung/tutorials/tree/master/spring-boot-modules/spring-boot-properties-2


原始标题:Inject a Map from a YAML File with Spring | Baeldung