在 Spring Boot 开发中,将配置文件(application.yml / application.properties)中的参数映射到 Java 对象,是日常开发最基础也最高频的操作。Spring 为我们提供了两种主流方案:@ConfigurationProperties 和 @Value。很多同学在初学时对两者的区别与选择感到困惑,今天我们就从用法、原理、对比到最佳实践,一次性彻底讲透。
一、背景:为什么要映射配置?
项目中的各种连接信息、业务开关、第三方参数通常不会硬编码在代码里,而是写在外部的配置文件中。当应用启动时,Spring 容器需要自动把这些字符串配置转换成 Java 对象供代码使用。这就是 配置属性注入 的核心任务。
Spring Boot 提供了两种核心方式:
- @ConfigurationProperties:批量绑定,适合一组相同前缀的配置
- @Value:单个注入,适合零散配置或需要 SpEL 表达式的场景
下面我们分别深入讲解。
二、@ConfigurationProperties ——批量绑定的利器
2.1 作用
把配置文件中同一前缀下的多个属性,自动、批量地注入到一个 Java Bean 的字段中。它非常适合一组相关联的配置,比如数据库参数、自定义业务规则、第三方服务地址等。
2.2 快速上手
第一步:添加可选依赖(强烈推荐)
从 Spring Boot 2.2 开始,此依赖不是必须的,但引入后可以获得 IDE 的配置属性提示,避免自己手写前缀时拼错。如果需要生成 spring-configuration-metadata.json 来给 yml 提示,也需引入。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional></dependency>
第二步:创建配置实体类
import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;import java.util.List;@Component // 交给Spring容器管理@ConfigurationProperties(prefix = "user.info") // 绑定前缀 user.infopublic class UserProperties { private String name; private Integer age; private List<String> tags; // 必须提供 getter / setter,底层通过反射调用 set 方法赋值 public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public List<String> getTags() { return tags; } public void setTags(List<String> tags) { this.tags = tags; }}
第三步:编写配置文件(application.yml)
user: info: name: zhangsan age: 22 tags: – java – spring
第四步:在业务代码中注入使用
@RestControllerpublic class UserController { @Autowired private UserProperties userProperties; @GetMapping("/user") public String getUser() { return userProperties.getName() + " – " + userProperties.getAge(); }}
2.3 进阶特性
- 嵌套对象与复杂结构支持 List、Map、嵌套对象等复杂结构,只需继续遵循 JavaBean 规范即可。
- 宽松绑定(Relaxed Binding)配置项的名称支持多种写法,会自动映射到驼峰命名的字段。例如 user.info.user-name、user.info.userName 和 user.info.USER_NAME 都能正确绑定到 userName 属性。
- JSR303 数据校验结合 @Validated 注解,可以对绑定后的属性进行校验,例如 @NotEmpty、@Min 等。如果校验失败,启动阶段就会报错,避免上线后才发现配置错误。@Component@ConfigurationProperties(prefix = "user.info")@Validatedpublic class UserProperties { @NotEmpty private String name; @Min(1) private Integer age; // getter/setter…}
- 与 @PropertySource 结合默认读取主配置文件(application.yml),如果需要加载自定义位置的 .properties 文件,可以在类上再加 @PropertySource("classpath:custom.properties")。
三、@Value ——轻量级的单值注入
3.1 作用
读取某个单一的配置项,直接注入到字段或方法参数中。适合只有一两个零散配置需要获取的场景。
3.2 使用示例
@Componentpublic class DemoConfig { @Value("${user.info.name}") private String name; @Value("${user.info.age:18}") // :18 表示默认值,当配置不存在时使用 18 private Integer age; // 也可以注入SpEL表达式 @Value("#{2 * 5}") private int computedValue; // 10}
3.3 @Value 的短板
虽然 @Value 方便,但在实际项目中暴露出几个明显问题:
四、核心对比(面试高频,务必记住)
| 批量注入 | ✅ 支持一组相同前缀的配置 | ❌ 只能单个字段注入 |
| 嵌套对象/List/Map | ✅ 完美支持 | ❌ 难以实现,需要额外处理 |
| 宽松绑定 | ✅ 支持(驼峰、横杠、下划线等) | ❌ 不支持 |
| 数据校验 | ✅ 结合 @Validated 即可 | ❌ 不支持 |
| SpEL 表达式 | ❌ 不能使用 | ✅ 支持 @Value("#{…}") |
| 使用复杂度 | 需要额外编写一个 Bean 类 | 直接声明在字段上,简单 |
| 适用场景 | 一组相关联的业务参数、第三方配置等 | 个别零散参数、需要SpEL时 |
从表中可以看出,@ConfigurationProperties 在工程化、规范性、可维护性上更胜一筹,是官方更推荐的配置绑定方式。
五、极易踩坑!这几个细节一定要注意
5.1 必须有 setter 方法
@ConfigurationProperties 底层通过反射调用属性的 setter 方法赋值。如果只提供了 getter 而没有 setter,属性将无法注入,不会报错但值为 null。这一点很多新手会忽略。
5.2 类必须被 Spring 管理
常见两种方式让配置类生效:
方式一:在类上加 @Component 等组件注解
@Component@ConfigurationProperties(prefix = "user.info")public class UserProperties { … }
方式二:在启动类或配置类上使用 @EnableConfigurationProperties
@SpringBootApplication@EnableConfigurationProperties(UserProperties.class)public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); }}
两种方式任选其一。若忘记配置,运行时会找不到该类对应的 Bean,导致 @Autowired 注入失败。
5.3 不要混淆 @Configuration 和 @ConfigurationProperties
- @Configuration:标识一个类是配置类,常用于定义 @Bean。
- @ConfigurationProperties:纯粹用于绑定外部配置,不代表它是一个配置类。两者功能完全不同,名字虽像但不可混用。
5.4 注意 @Value 取不到值的默认值
@Value("${key:default}") 中,冒号后面即为默认值。如果未配置且没有写默认值,启动时会报 IllegalArgumentException: Could not resolve placeholder。合理使用默认值可以提高应用的健壮性。
六、环境变量占位符的妙用
两种注解都支持读取系统环境变量及配置文件中占位符。常见场景如:
server: port: ${PORT:8080}custom: path: ${JAVA_HOME:/usr/local/java}/lib
在 @Value 中同样可以使用 ${…} 引用其他配置项或环境变量,提高了配置的灵活性。
七、如何选择?记住这两条原则
八、结语
@ConfigurationProperties 和 @Value 都是 Spring Boot 配置注入的核心手段,各有侧重。在实际项目中,推荐以 @ConfigurationProperties 为主、@Value 为辅的组合使用策略,既保证了配置的结构化,又不失灵活性。




