大数跨境
0
0

必须掌握SpringBoot强大的自定义属性配置

必须掌握SpringBoot强大的自定义属性配置 Spring全家桶实战案例
2024-05-25
1
导读:必须掌握SpringBoot强大的自定义属性配置

环境:SpringBoot3.3.0



1. 简介

在Spring Boot中,自定义配置属性的加载和绑定可以通过多种方式实现,其中@Value和@ConfigurationProperties是两种常用的注解。下面分别对这两种方式进行简介:

1.1 @Value注解

@Value注解主要用于将配置文件中的键对应的值分配给某类内带注解的属性。它可以直接将配置文件中的某个具体值注入到Spring管理的Bean的某个字段上。


2.2 @ConfigurationProperties注解

@ConfigurationProperties注解用于将外部配置文件中的属性值绑定到Java类的字段或属性上,特别适合处理复杂的配置属性。

2.3 两者对比

功能 @ConfigurationProperties @Value
宽松绑定 Yes 有限制
元数据支持 Yes No
SpEL表达式 No Yes

接下来会对@ConfigurationProperties注解的使用进行全方面的讲解,相信你一定会有收获的。

2. 实战案例

2.1 JavaBean属性绑定

这种属性绑定应该是我们工作中最为常用的

@Component@ConfigurationProperties("pack")public class PackProperties {  private boolean enabled;    private InetAddress remoteAddress;    private final Security security = new Security();    // getters, setters  public static class Security {        private String username;        private String password;        private List<String> roles = new ArrayList<>(Collections.singleton("USER"));        // getters, setters  }  }

配置文件

pack:  sys:    remote-address: 192.168.2.100    enabled: true    security:      roles: GUEST, ADMIN

扩展知识

如果我们将上面对应属性的setter方法删除,那么将会得到如下错误

在以下情况下,可以省略setter:

  • Map,只要它们被初始化了,就需要一个getter,但不一定需要一个setter,因为它们可以被绑定器改变,如下示例:

public class PackProperties {  // other  private Map<String, String> params = new HashMap<>() ;  // 不需要setter  public final Map<String, String> getParams() {    return this.params ;  }}

配置文件

pack:  sys:    params:      a: 1      b: 2

这里使用的Map集合,在这种情况下就不需要setter方法。

注:如果你没有没有对这里的params初始化,那么还是会报错。

  • 访问集合和数组既可以通过索引(通常使用YAML),也可以使用逗号分隔的值(properties)。在后一种情况下,setter是必须的。初始化集合时,要确保它不是不可变的,如下示例:

public class PackProperties {  // other  private final List<String> ids = new ArrayList<>() ;  // 不需要setter  public List<String> getIds() {    return this.id ;  }}

配置文件

pack:  sys:    ids:    - 2    - 6

如果是属性文件你还可以通过逗号分割

pack.sys.ids=2,6,9

这些情况下都不需要setter方法。

  • 如果初始化了嵌套的POJO属性(如前面示例中的Security字段),则不需要setter。

如上面的Security,就无需提供setter方法。

2.2 构造函数绑定

如下示例:

@ConfigurationProperties(prefix = "pack")public class PackConstructorProperties {  private Integer age ;  private String name ;  @DurationUnit(ChronoUnit.SECONDS)  private Duration expire ;  private Security security = new Security() ;  @ConstructorBinding  public PackConstructorProperties(Integer age, String name, Duration expire, Security security) {    this.age = age ;    this.name = name ;    this.expire = expire ;    this.security = security ;  }  public static class Security {    private String role ;  }}

通过@ContructorBinding注解标注在构造函数上。

在上面的情况下,你可以省略@ContructorBinding注解,如果你还有一个有属性绑定的构造函数是,那就必须使用该注解,如下示例:

public PackConstructorProperties(Integer age, String name, Duration expire, @DefaultValue Security security) {  this.age = age ;  this.name = name ;  this.expire = expire ;  this.security = security ;}@ConstructorBindingpublic PackConstructorProperties(Integer age, String name) {  this.age = age ;  this.name = name ;}

在上面情况下,你必须使用@ContructorBinding注解指定一个构造函数。

默认值设置

如下示例:

private Security security ;public PackConstructorProperties(Security security) {  // ...  this.security = security ;}

该示例中构造函数使用了嵌套对象,如果你的配置文件中没有配置security,那么得到的Security对象是null

PackConstructorProperties [security=null]

在此种情况如果你去使用Security就可能出现NPE情况;我们可以@DefaultValue注解设置一个默认值,如下示例:

public PackConstructorProperties(@DefaultValue Security security) {  // ...  this.security = security ;}

输出结果

PackConstructorProperties [security=Security[role=null]]

此时的Security对象不再是null。

注册为Bean

注意上面的代码,我们并没有在类上添加@Component注解,尝试添加该注解

启动报错了,根据提示得知,如果你使用了构造函数绑定那么你就只能通过@ConfigurationPropertiesScan@EnableConfigurationProperties定义

@Configuration@EnableConfigurationProperties({PackConstructorProperties.class})public class AppConfig {}

也可以直接定义自动扫描哪些包

@Configuration@ConfigurationPropertiesScan({ "com.pack.app", "com.pack.another" })public class PackApplication {}


2.3 record组件绑定

以上介绍的都普通java class绑定,在jdk16正式发布了record组件(jdk14开始提出预览版)。

@ConfigurationProperties(prefix = "pack.app")public record AppProperties(      String version,      String title,      Integer numbers    ) {}

注意,这里你通用不能使用@Component,也必须通过上面介绍的@ConfigurationPropertiesScan@EnableConfigurationProperties方式定义。

2.4 转换时间

Spring Boot专门支持表达持续时间。如果你定义了java.time.Duration属性,则以下格式可用:

  • 常规的long表示形式(使用毫秒作为默认单位,除非指定了@DurationUnit)

  • java.time.Duration使用的标准ISO-8601格式

  • 一种更可读的格式,其中值和单元耦合(10s表示10秒)

如下示例:

@Component@ConfigurationProperties("sys.times")public class PackTimeProperties {  @DurationUnit(ChronoUnit.SECONDS)  private Duration sessionTimeout = Duration.ofSeconds(30);  private Duration readTimeout = Duration.ofMillis(1000);  // getters, setters...}

配置文件

sys:  times:    read-timeout: 60    session-timeout: 6000ms

输出结果

PackTimeProperties [sessionTimeout=PT6S, readTimeout=PT0.06S]

sessionTimeout: 虽然在字段上添加了单位,但是我们的配置也同样添加了时间单位,最终以配置为主。
readTimeout: 没有添加单位,则默认以ms为单位。

注意:如果sessionTimeout设置的属性没有指定单位,纯数字,则单位以字段上设置的为主。

支持以下单位:

  • ns 纳秒

  • us 微秒

  • ms 毫秒

  • s 秒

  • m 分

  • h 小时

  • d 天

默认单位为毫秒,可以使用@DurationUnit覆盖。

2.5 转换数据大小

Spring有一个以字节表示大小的DataSize值类型。如果定义DataSize属性,则属性可用以下格式:

  • 常规的long表示(使用字节作为默认单位,除非指定了@DataSizeUnit)

  • 值和单位耦合在一起的更可读的格式(10MB表示10 mb)

如下示例:

@Component@ConfigurationProperties("sys.ds")public class PackDataSizeProperties {
@DataSizeUnit(DataUnit.MEGABYTES) private DataSize bufferSize = DataSize.ofMegabytes(2) ; private DataSize sizeThreshold = DataSize.ofBytes(512);}

配置文件

sys:  ds:    buffer-size: 10    size-threshold: 1024KB

输出结果

PackDataSizeProperties [bufferSize=10485760B, sizeThreshold=1048576B]

支持以下单位:

  • B 字节

  • KB

  • MB

  • GB

  • TB


2.6 数据验证

在配置属性类时,我们还可以指定验证规则,如下示例:

@ConfigurationProperties("pack")@Validatedpublic class MyProperties {  @NotNull  private InetAddress remoteAddress;  @Valid  private final Security security = new Security();}

关于验证相关的详细,请查看下面两篇文章:

Spring Boot启动时必须对配置信息做有效性校验

【技巧】API接口参数验证的必备神器,让你的代码更高效!

以上是本篇文章的全部内容,如对你有帮助就请作者吃个棒棒糖🍭。

推荐文章

从SpringBoot2.7开始自动配置发生哪些变化?你都知道吗?

Spring非常强大的2个类知道的人不多

接口响应慢?掌握这优化技巧速度飙升

Spring这个大坑要注意啦!会导致资源泄漏

SpringBoot项目中这10个开发技巧你都知道吗?

【高效开发】使用Spring Data JPA的QBE功能,轻松构建查询条件

SpringBoot这些条件注解助你高效开发

你以为只有Controller一种接口定义方式?详解Web函数式接口

这些强大的工具类助你提升开发效率

@InitBinder注解会用吗?该如何使用?

强大的异步任务处理类CompletableFuture使用详解

【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读38
粉丝0
内容832