1. 首页
  2. 后端

@ConfigurationProperties VS @Value,你觉得哪个更好用

  @ConfigurationProperties VS @Value,你觉得哪个更好用

===========================================

实际工作中,我们经常会看到或用到`@ConfigurationProperties`和`@Value` 注解来注入自定义配置属性,那它们之间有什么不同呢?本文将从松散绑定 、参数校验、SpEL表达式、元数据支持等多方面介绍两者之间的不同之处。

使用

先看一下怎么使用它们。

  1. 先自定义几个配置属性
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系列
  1. 使用 @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识别不到自定义的属性。

  1. 使用 @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.propertiesapplication.yml)属性提供详细的元数据信息,如属性的名称、数据类型、描述、默认值和废弃信息等。

下面用一个简单示例演示一下元数据的生成:

  1. 引入 spring-boot-configuration-processor
    Springboot版本是3.1.5 ,,不引入不会生成元数据文件
<dependency>
   <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
  1. 编译项目
    项目编译完成之后,在META-INF文件夹下可以看到 spring-configuration-metadata.json

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

QR code