@ConfigurationProperties VS @Value,你觉得哪个更好用
===========================================
实际工作中,我们经常会看到或用到`@ConfigurationProperties`和`@Value` 注解来注入自定义配置属性,那它们之间有什么不同呢?本文将从松散绑定 、参数校验、SpEL表达式、元数据支持等多方面介绍两者之间的不同之处。
使用
先看一下怎么使用它们。
- 先自定义几个配置属性
sun-coder-note.name=索码理
sun-coder-note.en_name=sunocdernote
# 粉丝数
sun-coder-note.fansCount=10000000
# 阅读数
sun-coder-note.read-count=10000000
sun-coder-note.article.title=自定义配置@ConfigurationProperties和@Value区别
sun-coder-note.article.category=springboot系列
- 使用 @ConfigurationProperties 注解接收自定义属性
定义一个SunCoderNoteProperties
类, 使用 @ConfigurationProperties 注解接收自定义属性
@Data
@Configuration
@ConfigurationProperties(prefix = "sun-coder-note")
public class SunCoderNoteProperties {
/**
* 中文名
*/
private String name;
/**
* 英文名
*/
private String enName;
/**
* 粉丝数
*/
private Integer fansCount;
/**
* 阅读数
*/
private Integer readCount;
/**
* 文章
*/
private ArticleProperties article;
}
通常情况下,在使用 @ConfigurationProperties 注解时,只要指定prefix前缀属性即可,同时 @Configuration 也要一起使用,要不然Springboot识别不到自定义的属性。
- 使用 @Value 注解获取自定义属性
在属性上使用 @Value 注解 ,使用 $ 符号直接获取自定义属性名对应的值。
@Data
@Configuration
public class SunCoderNoteValueProperties {
@Value("${sun-coder-note.name}")
private String name;
@Value("${sun-coder-note.en-name}")
private String enName;
@Value("${sun-coder-note.fans-count}")
private Integer fansCount;
@Value("${sun-coder-note.read-count}")
private Integer readCount;
}
测试
上面两个属性类定义好后,通过单元测试,测试能否获取到值。
@SpringBootTest
class PropertiesApplicationTests {
@Resource
private SunCoderNoteProperties sunCoderNoteProperties;
@Resource
private SunCoderNoteValueProperties sunCoderNoteValueProperties;
@Test
public void testBean(){
System.out.println(sunCoderNoteProperties);
System.out.println();
System.out.println(sunCoderNoteValueProperties);
}
}
通过测试,查看控制台,可以看到两种方式都能够获取到对应的属性值。
SunCoderNoteProperties(name=索码理, enName=sunocdernote, fansCount=10000000, readCount=10000000, article=ArticleProperties(title=自定义配置@ConfigurationProperties和@Value区别, category=springboot系列))
SunCoderNoteValueProperties(name=索码理, enName=sunocdernote, fansCount=10000000, readCount=10000000)
@ConfigurationProperties和@Value区别
既然 @ConfigurationProperties 和 @Value 都能够获取到自定义属性的值,那么它们之间有什么区别呢? 不用我说,聪明的你通过上面的使用示例也能看出一些区别,下面我会总结一下它们的区别并逐个进行介绍。
| 特性 | @ConfigurationProperties | @Value |
| — | — | — |
| 复杂类型封装 | 支持 | 不支持 |
| 松散绑定 | 支持 | 支持(有限制) |
| SpEL表达式 | 不支持 | 支持 |
| JSR-303 数据校验 | 支持 | 不支持 |
| 元数据支持 | 支持 | 不支持 |
复杂类型封装
- @ConfigurationProperties: 支持复杂类型的封装,比如上面的 ArticleProperties ,除此之外还支持列表、集合等。
- @Value: 通常只支持简单类型的封装,不适用于复杂类型的直接注入。
松散绑定
松散绑定是一种在属性绑定时提供灵活性的机制,它允许配置文件中的属性名与Java类中的字段名之间存在一定的差异,不需要严格匹配。
松散绑定支持多种不同的命名风格,包括驼峰式、短横线隔开式、下划线表示法 以及大写格式 。
- 短横线隔开式:建议在
.properties
和 YAML配置文件中使用。 - 下划线表示法:可以选择在
.properties
和 YAML配置文件中使用。 - 大写格式:建议在使用系统环境变量时使用。
下面举例说明一下:
示例:
以使用了 @ConfigurationProperties
注解的SunCoderNoteProperties
类的enName
属性为例。
- 在配置文件中,可以使用以下任意一种形式来配置该属性:
sun-coder-note.enName=sunocdernote
sun-coder-note.en-name=sunocdernote
sun-coder-note.en_name=sunocdernote
sun-coder-note.EN_NAME=sunocdernote
SpringBoot的松散绑定机制都可以自动将这些配置映射到SunCoderNoteProperties
类的enName
属性上。
但对于 @Value
注解来说,它是有一定的限制的,比如下面3种命名方式:
sun-coder-note.en-name=sunocdernote
sun-coder-note.en_name=sunocdernote
sun-coder-note.EN_NAME=sunocdernote
如果这样取值 @Value("${sun-coder-note.enName}")
,你会发现不仅取不到值,还会报错。
虽然松散绑定提供了很大的灵活性,但在实际应用中,建议尽量保持配置文件中的命名风格一致,以便更容易地理解和维护配置文件。
元数据支持
所谓元数据指的是在项目使用了 @ConfigurationProperties
注解时,在编译过程中由 SpringBoot 自动生成的文件的 spring-configuration-metadata.json
文件。该元数据文件主要用于为应用程序中的配置文件( application.properties
或 application.yml
)属性提供详细的元数据信息,如属性的名称、数据类型、描述、默认值和废弃信息等。
下面用一个简单示例演示一下元数据的生成:
- 引入
spring-boot-configuration-processor
Springboot版本是3.1.5 ,,不引入不会生成元数据文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
- 编译项目
项目编译完成之后,在META-INF文件夹下可以看到spring-configuration-metadata.json
具体格式如下:
{
"groups": [
{
"name": "sun-coder-note",
"type": "site.suncodernote.properties.SunCoderNoteProperties",
"sourceType": "site.suncodernote.properties.SunCoderNoteProperties"
}
],
"properties": [
{
"name": "sun-coder-note.article",
"type": "site.suncodernote.properties.ArticleProperties",
"description": "文章",
"sourceType": "site.suncodernote.properties.SunCoderNoteProperties"
},
{
"name": "sun-coder-note.en-name",
"type": "java.lang.String",
"description": "英文名",
"sourceType": "site.suncodernote.properties.SunCoderNoteProperties"
},
{
"name": "sun-coder-note.fans-count",
"type": "java.lang.Integer",
"description": "粉丝数",
"sourceType": "site.suncodernote.properties.SunCoderNoteProperties"
},
{
"name": "sun-coder-note.name",
"type": "java.lang.String",
"description": "中文名",
"sourceType": "site.suncodernote.properties.SunCoderNoteProperties"
},
{
"name": "sun-coder-note.read-count",
"type": "java.lang.Integer",
"description": "阅读数",
"sourceType": "site.suncodernote.properties.SunCoderNoteProperties"
}
],
"hints": []
}
SpEL表达式
SpEL表达式(Spring Expression Language) 是Spring框架中提供的一种强大的表达式语言,它用于在运行时查询和操作对象。
下面举个简单的示例看下 @Value 注解结合SpEL表达式的使用:
@Data
@Configuration
public class SunCoderNoteValueProperties {
/**
* 如果sun-coder-note.name自定义属性不存在,设置name默认值为suncodernote
*/
@Value("${sun-coder-note.name:suncodernote}")
private String name;
/**
* enName属性的值取site.suncodernote.validation.GenderEnum枚举类的MALE常量的name值
*/
@Value("#{T(site.suncodernote.validation.GenderEnum).MALE.name()}")
private String enName;
/**
* 如果sun-coder-note.fansCount的值小于1000,就让该值等于10,否则取该值
*/
@Value("#{${sun-coder-note.fansCount} < 1000 ? 10 : ${sun-coder-note.fansCount}}")
private Integer fansCount;
@Value("${sun-coder-note.read-count}")
private Integer readCount;
}
JSR-303 数据校验
之前的文章《初探Springboot 参数校验》中有介绍参数校验,感兴趣的可以去看看。
@ConfigurationProperties
注解标记的配置类中也是支持参数校验的,只需要在 @Validated ,然后在对应的属性上加上要约束的注解即可。
@Data
@Configuration
@ConfigurationProperties(prefix = "sun-coder-note")
@Validated
public class SunCoderNoteProperties {}
以上就是 @ConfigurationProperties 和 @Value 的区别。
总结
如果需要注入大量相关配置项,并且这些配置项有嵌套的结构或者集合形式,推荐使用 @ConfigurationProperties。
如果只是少量的配置项,或者希望使用SpEL表达式时,可以使用 @Value注解。
原文链接: https://juejin.cn/post/7385061036828737536
文章收集整理于网络,请勿商用,仅供个人学习使用,如有侵权,请联系作者删除,如若转载,请注明出处:http://www.cxyroad.com/17110.html