Spring Boot配置类的注解

cnblogs 2024-08-12 08:13:00 阅读 55

Spring Boot 中,若某类只用 @ConfigurationProperties 注解,然后该类:

    <li>没有在扫描路径下
  • 或没用 @Component 等注解

就会导致无法被扫描为 bean,须在配置类用 @EnableConfigurationProperties 注解去指定这个类,才能使 @ConfigurationProperties 生效,并作为一个 bean 添加进 Spring 容器。

@EnableConfigurationProperties 不能单独使用:

  • @EnableConfigurationProperties 和 @ConfigurationProperties组合使用
  • @EnableConfigurationProperties将@ConfigurationProperties所修饰的类添加到IoC容器

1 简介

Spring Boot外部化配置和轻松访问 Properties 文件中定义的属性。上文介绍了实现这一点的各种方法。

本文看Spring Boot 的 <code>@ConfigurationProperties。

2 项目设置

<parent>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-parent</artifactId>

<version>3.3.0</version>

<relativePath/>

</parent>

为验证文件中定义的属性,还需要一个 JSR-380 实现,hibernate-validator 就是其中之一,它由 spring-boot-starter-validation 依赖提供。

把它也添加到 pom.xml 中:

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-validation</artifactId>

</dependency>

更多详细信息可参阅 Hibernate Validator 入门。

3 示例属性

官方建议将配置属性隔离到单独 POJO,如:

@Configuration

@ConfigurationProperties(prefix = "mail")

public class ConfigProperties {

private String hostName;

private int port;

private String from;

}

通过 @Configuration,Spring 会在 Application Context 中创建一个 Spring Bean。

@ConfigurationProperties 适合具有相同前缀的分层属性。

Spring使用标准 Java Bean Setter,因此必须为每个属性声明Setter。

如不在 POJO 用 @Configuration,则需在 Spring Application main 类中添加 @EnableConfigurationProperties(ConfigProperties.class) 以将属性绑定到 POJO:

@SpringBootApplication

@EnableConfigurationProperties(ConfigProperties.class)

public class EnableConfigurationDemoApplication {

public static void main(String[] args) {

SpringApplication.run(EnableConfigurationDemoApplication.class, args);

}

}

Spring 会自动绑定属性文件中定义的、前缀为 mail 且名称与 ConfigProperties 类中某个字段相同的任何属性。

Spring 对绑定属性使用宽松规则,以下各种变体都可绑定到属性 hostName

mail.hostName

mail.hostname

mail.host_name

mail.host-name

mail.HOST_NAME

可用如下 properties 文件设置所有字段:

# 示例 properties

mail.hostname=host@mail.com

mail.port=9000

mail.from=mailer@mail.com

3.1、Spring Boot 2.2

从 Spring Boot 2.2 开始,Spring 通过 classpath 扫描查找并注册 @ConfigurationProperties 类。对 @ConfigurationProperties 扫描需通过添加 @ConfigurationPropertiesScan 来明确选择。

因此,不必用 @Component(及 @Configuration 等其他元注解)注解这种类,甚至也不必用 @EnableConfigurationProperties

@ConfigurationProperties(prefix = "mail")

@ConfigurationPropertiesScan

public class ConfigProperties {

private String hostName;

private int port;

private String from;

}

@SpringBootApplication 启用的 classpath Scanner 找到了 ConfigProperties 类,尽管我们没有用 @Component 对该类进行注解。

还可用@ConfigurationPropertiesScan扫描自定义位置的配置属性类:

@SpringBootApplication

@ConfigurationPropertiesScan("com.baeldung.configurationproperties")

public class EnableConfigurationDemoApplication {

public static void main(String[] args) {

SpringApplication.run(EnableConfigurationDemoApplication.class, args);

}

}

如上,Spring 将只在 com.baeldung.properties 包中查找配置属性类。

4 嵌套属性

可在 ListMapClass 中嵌套属性。

创建一个新的 Credentials 类,用于一些嵌套属性:

public class Credentials {

private String authMethod;

private String username;

private String password;

//Get、Set 方法

}

还需要更新 ConfigProperties 类,以便使用 ListMapCredentials 类:

public class ConfigProperties {

private String hostname;

private int port;

private String from;

private List<String> defaultRecipients;

private Map<String, String> additionalHeaders;

private Credentials credentials;

// Get、Set 省略

}

下面的属性文件将设置所有字段:

#Simple properties

mail.hostname=mailer@mail.com

mail.port=9000

mail.from=mailer@mail.com

#List properties

mail.defaultRecipients[0]=admin@mail.com

mail.defaultRecipients[1]=owner@mail.com

#Map Properties

mail.additionalHeaders.redelivery=true

mail.additionalHeaders.secure=true

#对象 properties

mail.credentials.username=john

mail.credentials.password=password

mail.credentials.authMethod=SHA1

5 @Bean 方法用 @ConfigurationProperties

当要将属性绑定到无法控制的第三方组件时,特别有用。

public class Item {

private String name;

private int size;

}

看咋在 @Bean 方法中使用 @ConfigurationProperties 将外部化属性绑定到 Item 实例:

@Configuration

public class ConfigProperties {

@Bean

@ConfigurationProperties(prefix = "item")

public Item item() {

return new Item();

}

}

任何 item 前缀的属性都将映射到 Spring Context 管理的 Item 实例。

6 属性校验

@ConfigurationProperties 使用 JSR-380 格式对属性进行验证。

例如,把 hostName 属性成为强制性属性:

@NotBlank

private String hostName;

接下来,把 authMethod 属性的长度设为 14 个字符:

@Length(max = 4, min = 1)

private String authMethod;

然后,port 属性是 102565536

@Min(1025)

@Max(65536)

private int port;

最后,from 属性必须与电子邮件地址格式相匹配:

@Pattern(regexp = "^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,6}$")

private String from;

这可以帮助减少代码中大量的 if - else 判断条件,使代码看起来更简洁明了。

如果其中任何一项验证失败,应用将无法启动,并抛出 IllegalStateException 异常。

Hibernate Validation 框架使用标准的 Java Bean Getter 和 Setter,因此必须为每个属性声明 Getter 和 Setter 方法。

7 属性类型转换

@ConfigurationProperties 支持多种类型的转换,可将属性绑定到相应的 Bean。

7.1 Duration

先来看看如何将属性转换为 Duration 对象。

这里有两个 Duration 类型的字段:

@ConfigurationProperties(prefix = "conversion")

public class PropertyConversion {

private Duration timeInDefaultUnit;

private Duration timeInNano;

...

}

配置属性如下:

conversion.timeInDefaultUnit=10

conversion.timeInNano=9ns

如上,字段 timeInDefaultUnit 的值为 10 毫秒,而 timeInNano 的值为 9 纳秒。

支持的单位有 nsusmssmhd,分别表示纳秒、微秒、毫秒、秒、分、小时和天。

默认单位是毫秒,这意味着如果不在数值旁边指定单位,Spring 就会将数值转换为毫秒。

还可以使用 @DurationUnit 来覆盖默认单位:

@DurationUnit(ChronoUnit.DAYS)

private Duration timeInDays;

对应的属性如下:

conversion.timeInDays=2

7.2、DataSize

同样,Spring Boot @ConfigurationProperties 也支持 DataSize 类型转换。

添加三个 DataSize 类型的字段:

private DataSize sizeInDefaultUnit;

private DataSize sizeInGB;

@DataSizeUnit(DataUnit.TERABYTES)

private DataSize sizeInTB;

相应的属性如下:

conversion.sizeInDefaultUnit=300

conversion.sizeInGB=2GB

conversion.sizeInTB=4

如上,sizeInDefaultUnit 的值是 300 字节,因为默认单位是字节。

支持的单位有 BKBMBGBTB。还可以使用 @DataSizeUnit 覆盖默认单位。

7.3、自定义 Converter

还可以添加自己的自定义 Converter,以支持将属性转换为特定的类类型。

添加一个简单的 Employee 类:

public class Employee {

private String name;

private double salary;

}

然后,创建一个自定义 Converter 来转换该属性:

conversion.employee=john,2000

把它转换为 Employee 类型:

private Employee employee;

需要实现 Converter 接口,然后使用 @ConfigurationPropertiesBinding 注解注册自定义 Converter

@Component

@ConfigurationPropertiesBinding

public class EmployeeConverter implements Converter<String, Employee> {

@Override

public Employee convert(String from) {

String[] data = from.split(",");

return new Employee(data[0], Double.parseDouble(data[1]));

}

}

8 不可变的 @ConfigurationProperties 绑定

从 Spring Boot 2.2 开始,可以使用 @ConstructorBinding 注解来绑定配置属性,而不是老式的 Setter 注入。

这基本上意味着 @ConfigurationProperties 注解的类现在可以是不可变的了。

在 Spring Boot 3 中,如果只有一个带参构造函数,那么构造函数绑定就是隐式的,不需要使用注解。但如果有多个构造函数,必须注解首选的那个:

@ConfigurationProperties(prefix = "mail.credentials")

public class ImmutableCredentials {

private final String authMethod;

private final String username;

private final String password;

@ConstructorBinding

public ImmutableCredentials(String authMethod, String username, String password) {

this.authMethod = authMethod;

this.username = username;

this.password = password;

}

public ImmutableCredentials(String username, String password) {

this.username = username;

this.password = password;

this.authMethod = "Default";

}

public String getAuthMethod() {

return authMethod;

}

public String getUsername() {

return username;

}

public String getPassword() {

return password;

}

}

如上,在使用 @ConstructorBinding 时,需要为构造函数提供想要绑定的所有参数。

注意,ImmutableCredentials 的所有字段都是 final 字段。此外,ImmutableCredentials 没有 Setter 方法。

此外,需要强调的是,要使用构造函数绑定,需要通过 @EnableConfigurationProperties@ConfigurationPropertiesScan 明确启用配置类。

9 Java 16 Record

Java 16 引入 Record 类型(JEP 395)。Record 类是不可变数据的透明载体。这使它们成为配置持有者和 DTO 的理想选择。事实上,可以在 Spring Boot 中将 Java Record 定义为配置属性。例如,前面的示例可重写为:

@ConstructorBinding

@ConfigurationProperties(prefix = "mail.credentials")

public record ImmutableCredentials(String authMethod, String username, String password) {

}

显然,它比那些模板式的 Getter 和 Setter 更简洁。

Spring Boot 2.6 开始,对于单构造函数 Record,可以不用 @ConstructorBinding 注解。但是,如果 Record 有多个构造函数,则仍应使用 @ConstructorBinding 来标识用于属性绑定的构造函数。

10 总结

本文介绍了如何在 Spring Boot 中使用 @ConfigurationProperties 来绑定配置属性,以及如何进行属性验证和属性转换。

关注我,紧跟本系列专栏文章,咱们下篇再续!

作者简介:魔都架构师,多家大厂后端一线研发经验,在分布式系统设计、数据平台架构和AI应用开发等领域都有丰富实践经验。

各大技术社区头部专家博主。具有丰富的引领团队经验,深厚业务架构和解决方案的积累。

负责:

  • 中央/分销预订系统性能优化
  • 活动&券等营销中台建设
  • 交易平台及数据中台等架构和开发设计
  • 车联网核心平台-物联网连接平台、大数据平台架构设计及优化
  • LLM Agent应用开发
  • 区块链应用开发
  • 大数据开发挖掘经验
  • 推荐系统项目

目前主攻市级软件项目设计、构建服务全社会的应用系统。

参考:

  • 编程严选网

本文由博客一文多发平台 OpenWrite 发布!



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。