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.yml
或 application.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
目标是:
application
→Map<String, String>
config
→Map<String, List<String>>
users
→Map<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 |
松散绑定 | 支持(如 contextPath ↔ context-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