Spring Boot 教程11:@ConfigurationProperties

本文介绍了SpringBoot中@ConfigurationProperties注解的使用,包括如何声明、外部化配置、属性松散绑定、嵌套属性、属性验证以及自定义转换器的实现。通过示例展示了如何将配置属性绑定到POJO,以及从2.2版本开始的新特性,如构造函数绑定和Java16的Record支持。
摘要由CSDN通过智能技术生成

Spring Boot 教程11:@ConfigurationProperties

声明

这个系列文章是翻译自https://www.baeldung.com/的系列博客,个人感觉是一个非常不错的Spring Boot 教程。原网站属于一个公司,主要开展有偿培训业务,但提供相关文字教程的免费阅读和下载。因为我并没有在网页找到相关版权描述信息,所以并不能确定是否可以自由翻译和转载,如果有版权问题,请联系我,我会撤下这个系列文章。

原文地址:Guide to @ConfigurationProperties in Spring Boot

因为版权的关系,本文禁止转载。


简介

Spring Boot 具有许多有用的功能,包括外部化配置和轻松访问属性文件中定义的属性。前面的教程描述了可以实现这一点的各种方法。

现在我们将更详细地探索 @ConfigurationProperties 注释。

设置

本教程使用了相当标准的设置。我们首先在pom.xml中添加 [spring-boot-starter-parent](https://search.maven.org/search?q=a:spring-boot-starter-parent AND g:org.springframework.boot) 作为父节点:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.0.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入门页面有更多细节。

简单属性

官方文档建议我们将配置属性隔离到单独的POJO中。

让我们从这开始:

@Configuration
@ConfigurationProperties(prefix = "mail")
public class ConfigProperties {
    
    private String hostName;
    private int port;
    private String from;

    // standard getters and setters
}

我们使用 @Configuration ,以便Spring在应用程序上下文中创建Spring bean。

@ConfigurationProperties 最适用于具有相同前缀的分层属性;因此,我们添加了一个邮件前缀。

Spring框架使用标准的Javabean setter,因此我们必须为每个属性声明setter。

注意:如果我们没有在POJO中使用 @Configuration ,那么我们需要在主Spring application类中添加 @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

因此,我们可以使用以下属性文件来设置所有字段:

#Simple properties
mail.hostname=host@mail.com
mail.port=9000
mail.from=mailer@mail.com

Spring Boot 2.2

从**Spring Boot 2.2开始,Spring通过classpath扫描查找并注册 @ConfigurationProperties 类。需要通过添加 @ConfigurationPropertiesScan 注释明确选择 @ConfigurationProperties 的扫描。因此,我们不必使用@Component(以及其他元注释,如*@Configuration*)来注释此类类,甚至不必使用*@EnableConfigurationProperties*:

@ConfigurationProperties(prefix = "mail") 
@ConfigurationPropertiesScan 
public class ConfigProperties { 

    private String hostName; 
    private int port; 
    private String from; 

    // standard getters and setters 
}

@SpringBootApplication 启用的类路径扫描器会找到 ConfigProperties 类,即使我们没有用 @Component. 注释该类。

此外,我们可以使用 [@ConfigurationPropertiesScan](ConfigurationPropertiesScan (Spring Boot Docs 2.2.0.RELEASE API) — ConfigurationPropertiesScan(Spring靴子Docs 2.2.0.RELEASE API)) 注释来扫描配置属性类的自定义位置:

@SpringBootApplication
@ConfigurationPropertiesScan("com.baeldung.configurationproperties")
public class EnableConfigurationDemoApplication { 

    public static void main(String[] args) {   
        SpringApplication.run(EnableConfigurationDemoApplication.class, args); 
    } 
}

这样Spring将只在 com.baeldung.properties 包中查找配置属性类。

嵌套属性

我们可以在列表、映射和类中嵌套属性。

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

public class Credentials {
    private String authMethod;
    private String username;
    private String password;

    // standard getters and setters
}

我们还需要更新 ConfigProperties 类以使用List、Map和Credentials类:

public class ConfigProperties {

    private String hostname;
    private int port;
    private String from;
    private List<String> defaultRecipients;
    private Map<String, String> additionalHeaders;
    private Credentials credentials;
 
    // standard getters and setters
}

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

#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

#Object properties
mail.credentials.username=john
mail.credentials.password=password
mail.credentials.authMethod=SHA1

在 @Bean 方法上使用 @ConfigurationProperties

我们还可以在@Bean注释的方法上使用@ConfigurationProperties注释。

当我们想要将属性绑定到我们无法控制的第三方组件时,这种方法可能特别有用。

让我们创建一个简单的 Item 类,我们将在下一个示例中使用:

public class Item {
    private String name;
    private int size;

    // standard getters and setters
}

现在让我们看看如何在 @Bean 方法上使用 @ConfigurationProperties 来将外部化属性绑定到Item实例:

@Configuration
public class ConfigProperties {

    @Bean
    @ConfigurationProperties(prefix = "item")
    public Item item() {
        return new Item();
    }
}

因此,任何以item为前缀的属性都将映射到Spring上下文管理的Item实例。

属性验证

@ConfigurationProperties 使用JSR-380格式提供属性验证。这允许各种各样的整洁的事情。

例如,让我们将 hostName 属性设置为强制属性:

@NotBlank
private String hostName;

接下来,让我们将 authMethod 属性的长度设置为1到4个字符:

@Length(max = 4, min = 1)
private String authMethod;

然后是从1025到65536的端口属性:

@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 验证框架使用标准的Javabean getter和setter,因此为每个属性声明getter和setter非常重要。

属性转换

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

持续时间

我们将从将属性转换为 Duration 对象开始。

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

@ConfigurationProperties(prefix = "conversion")
public class PropertyConversion {

    private Duration timeInDefaultUnit;
    private Duration timeInNano;
    ...
}

这是我们的属性文件:

conversion.timeInDefaultUnit=10
conversion.timeInNano=9ns

因此,字段 timeInDefaultUnit 将具有10毫秒的值,并且 timeInNano 将具有9纳秒的值。

支持的单位分别为纳秒、微秒、毫秒、秒、分钟、小时和天的ns、us、ms、s、m、h和d。

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

我们也可以使用 @DurationUnit: 覆盖默认单位

@DurationUnit(ChronoUnit.DAYS)
private Duration timeInDays;

这是相应的属性:

conversion.timeInDays=2

数据大小

同样,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字节,因为默认单位是字节。

支持的单位为B、KB、MB、GB和TB。我们也可以使用 @DataSizeUnit. 覆盖默认单位

自定义转换器

我们还可以添加自己的自定义转换器来支持将属性转换为特定的类类型。

让我们添加一个简单的类 Employee

public class Employee {
    private String name;
    private double salary;
}

然后我们将创建一个自定义转换器来转换此属性:

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]));
    }
}

不可变 @ConfigurationProperties 绑定

从Spring Boot 2.2开始,我们可以使用 @ConstructorBinding 注解来绑定配置属性。

这实质上意味着 @ConfigurationProperties 注释的类现在可以是不可变的。

但是从Spring Boot 3开始,这个注解不是必需的:

@ConfigurationProperties(prefix = "mail.credentials")
public class ImmutableCredentials {

    private final String authMethod;
    private final String username;
    private final String password;

    public ImmutableCredentials(String authMethod, String username, String password) {
        this.authMethod = authMethod;
        this.username = username;
        this.password = password;
    }

    public String getAuthMethod() {
        return authMethod;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }
}

正如我们所看到的,当使用 @ConstructorBinding, 时,我们需要为构造函数提供我们想要绑定的所有参数。

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

此外,需要强调的是,要使用构造函数绑定,我们需要使用 @EnableConfigurationProperties 或*@ConfigurationPropertiesScan* 显式启用配置类。

Java 16 records

Java 16将 record 类型作为JEP 395的一部分引入。records 是充当不可变数据的透明载体的类。这使它们成为配置持有者和DTO的完美候选者。事实上,我们可以在Spring Boot 中将Java records 定义为配置属性。例如,前面的示例可以重写为:

@ConstructorBinding
@ConfigurationProperties(prefix = "mail.credentials")
public record ImmutableCredentials(String authMethod, String username, String password) {
}

显然,与那些嘈杂的getter和setter相比,它更简洁。

此外,从Spring Boot 2.6开始,对于单构造函数记录,我们可以删除 @ConstructorBinding 注释。但是,如果我们的记录有多个构造函数,那么 @ConstructorBinding 仍然应该用来标识用于属性绑定的构造函数。

结论

在本文中,我们探索了 @ConfigurationProperties 注释,并强调了它提供的一些有用特性,比如宽松绑定和Bean验证。

像往常一样,代码可以在Github上找到。

Spring Boot中,可以使用@ConfigurationProperties注解来将配置文件中的属性值与Java对象进行绑定。这样可以方便地管理应用程序的配置属性。 下面是使用@ConfigurationProperties注解的步骤: 1. 创建一个Java类,并在类上添加@ConfigurationProperties注解。该注解的value属性指定了配置文件中的前缀,prefix属性指定了配置文件中的属性前缀。例如,如果配置文件中的属性为myconfig.name,那么可以将value属性设置为"myconfig"。 ```java @ConfigurationProperties(prefix = "myconfig") public class MyConfigProperties { private String name; // getter和setter方法 } ``` 2. 在配置文件(application.properties或application.yml)中定义属性值。例如,在application.properties中添加以下内容: ``` myconfig.name=bj ``` 3. 在Spring Boot应用程序的主类中,使用@EnableConfigurationProperties注解来启用@ConfigurationProperties注解。将@ConfigurationProperties注解的类作为参数传递给@EnableConfigurationProperties注解。 ```java @SpringBootApplication @EnableConfigurationProperties(MyConfigProperties.class) public class MyApp { public static void main(String[] args) { SpringApplication.run(MyApp.class, args); } } ``` 现在,可以在其他组件中注入使用@ConfigurationProperties注解的类,并使用其中的属性值。例如,在一个Service类中注入MyConfigProperties类: ```java @Service public class MyService { private final MyConfigProperties configProperties; public MyService(MyConfigProperties configProperties) { this.configProperties = configProperties; } public void printName() { System.out.println("Name: " + configProperties.getName()); } } ``` 这样,就可以在应用程序中使用@ConfigurationProperties注解来管理配置属性了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值