Spring Boot 的@ConfigurationProperties与@Value,@PropertySource
@ConfigurationProperties(prefix = "jwt") 是 Spring Boot 里超核心的注解,清楚它的作用、用法和核心价值。
一、核心作用:把配置文件的 jwt.* 绑定到 Java 类
简单说:它能自动把 application.yml/application.properties 里以 jwt 为前缀的配置项,赋值到标注了这个注解的类的字段上。
举个例子:你的配置文件里写了:
jwt:
secret: abcdefghijklmnopqrstuvwxyz123456
expiration: 7200000
clock-skew-seconds: 300
你的 JwtProperties 类里写了:
@Data
@Component
@ConfigurationProperties(prefix = "jwt") // 前缀指定为 jwt
public class JwtProperties {
private String secret; // 对应 jwt.secret
private Long expiration; // 对应 jwt.expiration
private Long clockSkewSeconds; // 对应 jwt.clock-skew-seconds(自动转驼峰)
}
✅ 效果:Spring 启动时,会自动把配置里的 jwt.secret 赋值给 JwtProperties.secret,jwt.expiration 赋值给 JwtProperties.expiration,不用你手动写 getValue("jwt.secret") 这种代码!
二、关键特性(为什么不用手动读取配置?)
1. 自动格式转换
- 配置里的
7200000(字符串)→ 自动转成Long类型赋值给expiration; - 配置里的
jwt.clock-skew-seconds(短横线命名)→ 自动匹配类里的clockSkewSeconds(驼峰命名),不用手动对应。
2. 类型安全
如果配置里写了非数字(比如 expiration: abc),Spring 启动时会直接报错,而不是运行时才发现类型不对,提前规避 bug。
3. 批量绑定
一个注解就能绑定所有 jwt.* 配置,不用写一堆 @Value("${jwt.secret}") 注解(尤其是配置项多的时候,超省心)。
对比一下两种写法:
表格
用 @ConfigurationProperties(推荐) |
用 @Value(繁琐) |
|---|---|
| 只需要一个注解,批量绑定 | 每个字段都要加 @Value |
| 支持类型自动转换、校验 | 手动转换类型,容易出错 |
| 代码整洁,配置项多的时候更易维护 | 配置项多了代码乱糟糟 |
三、使用条件(缺一不可)
- 必须加
@Component(或@Configuration):让 Spring 把这个类当成 Bean 管理,才能自动赋值; - 前缀要匹配:
prefix = "jwt"要和配置里的顶级节点jwt一致; - 字段名要匹配:配置里的
clock-skew-seconds对应类里的clockSkewSeconds(短横线转驼峰是 Spring 的默认规则)。
四、和 @Value 的核心区别
| 特性 | @ConfigurationProperties |
@Value |
|---|---|---|
| 批量绑定 | ✅ 支持(一个注解绑所有) | ❌ 单个绑定 |
| 短横线转驼峰 | ✅ 自动支持 | ❌ 手动写 ${jwt.clock-skew-seconds} |
| 类型转换 | ✅ 自动(String→Long/Integer) | ❌ 手动转换(比如 @Value("${jwt.expiration}") Long expiration) |
| 启动时校验 | ✅ 配置错误启动失败 | ❌ 运行时才报错 |
| 适合场景 | 多个配置项(比如 JWT、数据库) | 单个配置项(比如 app.name) |
总结
@ConfigurationProperties(prefix = "jwt")的核心是自动绑定配置文件中jwt.*到 Java 类,替代繁琐的手动读取;- 比
@Value更适合 “一组相关配置”(比如 JWT 的 secret / 过期时间 / 时钟偏移),类型安全、易维护;
@Value 注解做全方位拆解
一、@Value 核心定义
@Value 是 Spring 提供的核心注解,核心作用是:将单个配置项(来自配置文件 / 环境变量 / 命令行)绑定到 Java 类的字段上,支持直接值、占位符、SpEL 表达式,灵活度极高。
简单说:只要是 Spring 能识别的配置(不管是 application.yml、自定义 .properties,还是环境变量),都能用 @Value 精准 “拎出来” 赋值给字段。
二、基础用法(直接套用)
1. 绑定配置文件中的普通值
yaml
# application.yml 中的配置
app:
name: 我的应用
port: 8080
debug: true
@Component // 必须交给Spring管理,@Value才会生效
public class AppConfig {
// 绑定字符串
@Value("${app.name}")
private String appName;
// 绑定数字(自动类型转换)
@Value("${app.port}")
private Integer appPort;
// 绑定布尔值
@Value("${app.debug}")
private Boolean appDebug;
// 初始化时打印验证
@PostConstruct
public void printConfig() {
System.out.println("appName: " + appName); // 输出:我的应用
System.out.println("appPort: " + appPort); // 输出:8080
System.out.println("appDebug: " + appDebug); // 输出:true
}
}
2. 加默认值(避坑核心)
如果配置项不存在,直接写 @Value("${app.version}") 会导致 Spring 启动失败,必须加默认值:
// 语法:${配置项:默认值}
@Value("${app.version:1.0.0}") // 配置不存在时用 1.0.0
private String appVersion;
@Value("${app.timeout:3000}") // 默认值支持数字
private Integer appTimeout;
@Value("${app.enable:true}") // 默认值支持布尔
private Boolean appEnable;
3. 绑定环境变量 / 命令行参数
@Value 能读取环境变量、命令行参数(优先级高于配置文件):
# 1. 设置环境变量
export JWT_SECRET=abc123
# 2. 启动应用时传命令行参数
java -jar app.jar --app.name=命令行应用
@Component
public class EnvConfig {
// 读取环境变量
@Value("${JWT_SECRET:默认密钥}")
private String jwtSecret;
// 读取命令行参数(覆盖配置文件的 app.name)
@Value("${app.name}")
private String appName;
@PostConstruct
public void print() {
System.out.println("jwtSecret: " + jwtSecret); // 输出:abc123
System.out.println("appName: " + appName); // 输出:命令行应用
}
}
三、高级用法(SpEL 表达式)
@Value 支持 Spring 表达式(SpEL),能做简单计算、取值、判断,语法:#{表达式}:
@Component
public class SpELConfig {
// 1. 直接赋值(无需配置文件)
@Value("直接写的值")
private String directValue; // 输出:直接写的值
// 2. 数学计算
@Value("#{10 * 60 * 1000}") // 10分钟(毫秒)
private Long tenMinutes; // 输出:600000
// 3. 拼接字符串
@Value("#{'应用名称:' + '${app.name}'}")
private String appNameDesc; // 输出:应用名称:我的应用
// 4. 读取系统属性
@Value("#{systemProperties['user.name']}")
private String userName; // 输出:当前系统用户名
// 5. 条件判断
@Value("#{${app.debug} ? '调试模式' : '生产模式'}")
private String runMode; // app.debug=true 时输出:调试模式
}
四、避坑指南
1. ❌ 忘记加 @Component(或 @Service/@Controller 等)
@Value 只有在 Spring 管理的 Bean 中才会生效,普通类中使用会赋值失败(字段为 null):
// 错误写法:普通类,@Value 无效
public class NormalClass {
@Value("${app.name}")
private String appName; // null
}
// 正确写法:交给 Spring 管理
@Component
public class SpringBeanClass {
@Value("${app.name}")
private String appName; // 正常赋值
}
2. ❌ 配置项不存在且无默认值
// 错误:app.xxx 不存在,启动时报错
@Value("${app.xxx}")
private String xxx;
// 正确:加默认值
@Value("${app.xxx:默认值}")
private String xxx;
3. ❌ 类型不匹配
配置项是字符串,但字段是数字 / 布尔,Spring 会自动转换,但转换失败会报错:
yaml
# 配置
app:
port: abc # 非数字
// 错误:String → Integer 转换失败,启动报错
@Value("${app.port}")
private Integer appPort;
// 避免:加默认值(默认值类型要匹配)
@Value("${app.port:8080}")
private Integer appPort; // 用默认值 8080
4. ❌ 静态字段无法赋值
@Value 不能直接给静态字段赋值,需通过 setter 方法:
@Component
public class StaticConfig {
// 错误:静态字段直接赋值,结果为 null
@Value("${app.name}")
private static String appName;
// 正确:通过非静态 setter 赋值
private static String staticAppName;
@Value("${app.name}")
public void setStaticAppName(String appName) {
StaticConfig.staticAppName = appName;
}
}
五、@Value vs @ConfigurationProperties(核心区别)
| 场景 | 选 @Value |
选 @ConfigurationProperties |
|---|---|---|
| 配置数量 | 单个 / 少量配置项(如 app.name) |
一组相关配置(如 JWT、数据库配置) |
| 灵活性 | 支持 SpEL 表达式、环境变量、命令行参数 | 仅支持配置文件绑定,不支持 SpEL |
| 类型安全 | 运行时才报错(如类型转换失败) | 启动时校验,提前暴露问题 |
| 代码整洁度 | 配置多时代码繁琐(每个字段都要加注解) | 一个注解批量绑定,代码整洁 |
| 默认值 | 支持(${key:默认值}) |
需在字段上手动赋值(如 private Long expiration = 7200000L) |
六、最佳实践
- 零散配置:用
@Value + 默认值(如app.name、server.port); - 敏感配置:用
@Value("${JWT_SECRET:默认值}")(读取环境变量,避免硬编码); - 复杂逻辑:用 SpEL 表达式(如计算、拼接、条件判断);
- 一组配置:优先用
@ConfigurationProperties(如 JWT、Redis 配置); - 必选配置:
@Value("${key}")(无默认值,强制要求配置,启动失败时快速定位问题)。
总结
@Value核心是单个配置项绑定,灵活度高,支持占位符、SpEL、环境变量;- 避坑关键:加默认值、交给 Spring 管理、避免静态字段直接赋值;
- 少量配置用
@Value,一组配置用@ConfigurationProperties; - 生产环境中,敏感配置(如密钥)优先通过
@Value读取环境变量,而非硬编码。
@PropertySource 核心定义
@PropertySource 是 Spring 提供的注解,核心作用是:加载 application.yml/properties 之外的自定义配置文件(默认 Spring 只加载 resources 下的 application 系列配置)。
简单说:如果你的配置不在 application.yml 里,而是放在 custom.properties/custom.yml 里,就需要用这个注解告诉 Spring “去加载这个文件”。
一、基础用法
1. 加载单个 .properties 文件(最常用)
// 1. 新建自定义配置文件:resources/custom.properties
custom.key=hello
custom.value=123
custom.desc=自定义配置
// 2. 配置类中加载该文件
@Configuration
// value:配置文件路径(classpath 指 resources 目录)
// encoding:指定编码,避免中文乱码
@PropertySource(value = "classpath:custom.properties", encoding = "UTF-8")
public class CustomConfig {
// 3. 用 @Value 绑定配置(@PropertySource 只加载文件,不绑定配置)
@Value("${custom.key}")
private String customKey;
@Value("${custom.value:456}") // 加默认值,避免配置不存在时报错
private Integer customValue;
// 测试输出
@PostConstruct
public void printConfig() {
System.out.println("custom.key: " + customKey); // 输出 hello
System.out.println("custom.value: " + customValue); // 输出 123
}
}
2. 加载多个配置文件(用 @PropertySources)
@Configuration
@PropertySources({
@PropertySource("classpath:custom1.properties"),
@PropertySource("classpath:custom2.properties") // 可加载多个
})
public class MultiConfig {
@Value("${custom1.key}")
private String key1;
@Value("${custom2.key}")
private String key2;
}
三、避坑点(新手最容易踩)
1. ❌ 默认不支持 YAML 文件(.yml)
@PropertySource 原生只认识 .properties,直接加载 .yml 会失败:
// 错误写法:直接加载 custom.yml 会读不到配置
@PropertySource("classpath:custom.yml")
✅ 解决:自定义 YAML 加载器(两步搞定)
// 步骤1:自定义 YAML 加载器(可复用)
public class YamlPropertySourceLoader implements PropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
// 加载 YAML 文件为 Properties 对象
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(resource.getResource());
Properties properties = factory.getObject();
// 返回 PropertySource(用文件名作为名称)
return new PropertiesPropertySource(resource.getResource().getFilename(), properties);
}
}
// 步骤2:使用自定义加载器加载 YAML
@Configuration
@PropertySource(
value = "classpath:custom.yml",
factory = YamlPropertySourceLoader.class, // 指定自定义加载器
encoding = "UTF-8"
)
public class YamlConfig {
@Value("${custom.key}")
private String customKey;
}
2. ❌ 配置文件路径写错
- 正确路径:
classpath:custom.properties(classpath指向src/main/resources); - 错误路径:
classpath:/custom.properties(多了斜杠)、custom.properties(少了classpath:); - 如果文件在
resources/config下:classpath:config/custom.properties。
3. ❌ 配置项不存在时无默认值
如果 custom.key 不存在,@Value("${custom.key}") 会直接报错,建议加默认值:
// 正确写法:冒号后是默认值
@Value("${custom.key:默认值}")
private String customKey;
四、高级用法(结合 @ConfigurationProperties 批量绑定)
如果自定义配置文件里有一组相关配置(比如 pay.ali.app-id、pay.ali.private-key),可以结合 @ConfigurationProperties 批量绑定,比 @Value 更整洁:
// 1. 自定义配置文件:resources/pay.properties
pay.ali.app-id=123456
pay.ali.private-key=abcdefg
pay.ali.timeout=3000
// 2. 配置类
@Configuration
@PropertySource("classpath:pay.properties")
public class PayConfig {
// 3. 批量绑定 pay.ali 前缀的配置
@Bean
@ConfigurationProperties(prefix = "pay.ali")
public AliPayProperties aliPayProperties() {
return new AliPayProperties();
}
// 4. 配置类
@Data
public static class AliPayProperties {
private String appId; // 对应 pay.ali.app-id(自动转驼峰)
private String privateKey; // 对应 pay.ali.private-key
private Integer timeout; // 对应 pay.ali.timeout
}
// 测试
@PostConstruct
public void printPayConfig() {
System.out.println("appId: " + aliPayProperties().getAppId()); // 123456
}
}
五、和 application.yml 的配合使用
@PropertySource 加载的配置,优先级低于 application.yml,但高于默认值:
yaml
# application.yml(优先级更高)
custom.key=application里的值
properties
# custom.properties
custom.key=custom里的值
@Value("${custom.key:默认值}")
private String customKey; // 最终值是 "application里的值"
六、核心总结
- 核心作用:加载
application系列之外的自定义配置文件; - 基础用法:
@PropertySource("classpath:xxx.properties") + @Value; - 避坑重点:
- 原生不支持 YAML,需自定义加载器;
- 路径要写对(
classpath:开头); @Value加默认值避免空指针;
- 最佳实践:
- 零散配置:
@PropertySource + @Value; - 一组配置:
@PropertySource + @ConfigurationProperties; - 中文配置:一定要加
encoding = "UTF-8"。
- 零散配置:
1. @PropertySource 注意事项
- ❌ 默认不支持 YAML 文件(如
custom.yml),只能加载.properties;若要加载 YAML,需引入依赖 + 自定义加载器:xml
<!-- 引入依赖 --> <dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> </dependency>// 自定义 YAML 加载器 public class YamlPropertySourceLoader extends PropertySourceFactory { @Override public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException { YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean(); factory.setResources(resource.getResource()); Properties properties = factory.getObject(); return new PropertiesPropertySource(resource.getResource().getFilename(), properties); } } // 使用 @PropertySource(value = "classpath:custom.yml", factory = YamlPropertySourceLoader.class) - ✅ 支持指定编码(如
encoding = "UTF-8"),避免中文乱码。
2. 配置优先级(覆盖规则)
Spring Boot 配置加载优先级从高到低:
命令行参数 > 环境变量 > 自定义配置文件(@PropertySource)> application-{profile}.yml > application.yml
比如:命令行传 --jwt.secret=123 会覆盖 application.yml 里的 jwt.secret。
3. @ConfigurationProperties 高级用法
-
配置校验:配合
@Validated+ JSR380 注解校验配置合法性:@Data @Component @Validated @ConfigurationProperties(prefix = "jwt") public class JwtProperties { @NotBlank(message = "jwt.secret 不能为空") private String secret; @Min(value = 3600000, message = "jwt.expiration 不能小于1小时") private Long expiration; }若配置不满足,Spring 启动时直接报错,提前规避问题。
-
松散绑定:支持多种命名格式匹配:配置里的
jwt.clock-skew-seconds↔ 类里的clockSkewSeconds(驼峰)/clock-skew-seconds(短横线)/CLOCK_SKEW_SECONDS(大写下划线),无需严格一致。
三、最佳实践(新手直接套用)
| 场景 | 推荐方案 |
|---|---|
| 一组相关配置(如 JWT、数据库) | @ConfigurationProperties + @Component(批量绑定 + 类型安全) |
单个配置项(如 app.name) |
@Value("${app.name:默认值}")(灵活 + 加默认值避免空指针) |
加载自定义配置文件(如 custom.properties) |
@PropertySource + @Value/@ConfigurationProperties |
| 多环境配置(开发 / 测试 / 生产) | application-dev.yml + application-prod.yml + spring.profiles.active |
| 生产环境敏感配置(如 JWT 密钥) | 环境变量 + ${JWT_SECRET:默认值}(避免硬编码) |
@ConfigurationProperties、@Value、@PropertySource列表比对
一、核心配置读取方式汇总表
| 注解 / 方式 | 核心作用 | 语法示例 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|---|
@ConfigurationProperties |
批量绑定配置文件中同一前缀的配置项到 Java 类(类型安全) | java<br>@Data<br>@Component<br>@ConfigurationProperties(prefix = "jwt")<br>public class JwtProperties {<br> private String secret;<br> private Long expiration;<br>} |
1. 批量绑定,代码整洁2. 自动类型转换3. 短横线转驼峰4. 启动时校验配置 | 1. 只能绑定前缀下的配置2. 需配合 @Component |
一组相关配置(如 JWT、数据库、Redis 配置) |
@Value |
单个绑定配置文件中的任意配置项(支持 SpEL 表达式) | java<br>@Component<br>public class Test {<br> @Value("${jwt.secret}")<br> private String secret;<br> @Value("${jwt.expiration:7200000}") // 加默认值<br> private Long expiration;<br>} |
1. 灵活,可绑定任意配置2. 支持默认值3. 支持 SpEL(如 @Value("#{10*60*1000}")) |
1. 单个绑定,配置多时代码繁琐2. 类型转换需手动保证3. 运行时才报错(非启动时) | 单个 / 少量配置项(如 app.name、server.port) |
@PropertySource |
加载自定义路径 / 格式的配置文件(默认只加载 application.yml/properties) | java<br>@Configuration<br>@PropertySource(value = "classpath:custom.properties", encoding = "UTF-8")<br>public class CustomConfig {<br> @Value("${custom.key}")<br> private String customKey;<br>} |
1. 加载非默认配置文件(如 custom.properties)2. 支持指定编码 |
1. 只加载文件,不绑定配置2. 需配合 @Value/@ConfigurationProperties 使用3. 默认不支持 YAML(需额外依赖) |
加载自定义配置文件(如业务配置、第三方配置) |
@PropertySources |
批量加载多个自定义配置文件(@PropertySource 的批量版) |
java<br>@Configuration<br>@PropertySources({<br> @PropertySource("classpath:custom1.properties"),<br> @PropertySource("classpath:custom2.properties")<br>})<br>public class MultiConfig {} |
批量加载多个配置文件,语法更简洁 | 同 @PropertySource 的缺点 |
需加载多个自定义配置文件时 |
二、核心总结
@ConfigurationProperties:批量绑定 “一组配置”,类型安全,启动时校验,适合框架 / 组件配置(如 JWT、数据库);@Value:灵活绑定 “单个配置”,支持 SpEL,适合零散配置;@PropertySource:加载 “自定义配置文件”,需配合前两者使用,默认只支持.properties;- 优先级:命令行 > 环境变量 > 自定义配置 > 环境配置 > 默认配置;
- 生产环境:敏感配置(如密钥)用环境变量,避免硬编码在配置文件里。
更多推荐



所有评论(0)