springboot - 配置文件 @ConfigurationProperties
1.简单属性
@Configuration
@ConfigurationProperties(prefix = "mail")
public class ConfigProperties {
private String hostName;
private int port;
private String from;
// standard getters and setters
}
注意:如果我们不在POJO中使用@Configuration ,那么我们需要在主Spring应用程序类中添加@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
2.spring2.2
从Spring Boot 2.2开始,Spring 通过类路径扫描查找并注册@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注释 来扫描配置属性类的自定义位置:
@SpringBootApplication
@ConfigurationPropertiesScan("com.baeldung.configurationproperties")
public class EnableConfigurationDemoApplication {
public static void main(String[] args) {
SpringApplication.run(EnableConfigurationDemoApplication.class, args);
}
}
3.嵌套属性
public class Credentials {
private String authMethod;
private String username;
private String password;
// standard getters and setters
}
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
4.在@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();
}
}
5.属性验证
例如,让我们强制设置hostName属性:
@NotBlank
private String hostName;
@Length(max = 4, min = 1)
private String authMethod;
@Min(1025)
@Max(65536)
private int port;
@Pattern(regexp = "^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,6}$")
private String from;
6.时间类型
@ConfigurationProperties(prefix = "conversion")
public class PropertyConversion {
private Duration timeInDefaultUnit;
private Duration timeInNano;
...
}
配置文件:
conversion.timeInDefaultUnit=10
conversion.timeInNano=9ns
我们还可以使用 @DurationUnit 覆盖默认单位:
@DurationUnit(ChronoUnit.DAYS)
private Duration timeInDays;
conversion.timeInDays=2
7.数据大小 - 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 覆盖默认单位。
8.定制转换器
我们还可以添加自己的自定义转换器来支持将属性转换为特定的类类型。
让我们添加一个简单的Employee类:
public class Employee {
private String name;
private double salary;
}
然后我们将创建一个自定义转换器来转换此属性:
conversion.employee=john,2000
我们需要实现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]));
}
}
9.不可变的@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的所有字段 都是最终字段。此外,没有 setter 方法。
此外,需要强调的是,要使用构造函数绑定,我们需要使用 @EnableConfigurationProperties 或 @ConfigurationPropertiesScan显式启用我们的配置类。
10.Java 16记录
Java 16 引入了 记录 类型作为JEP 395的一部分。记录是充当不可变数据的透明载体的类。这使它们成为配置持有者和 DTO 的完美候选者。事实上,我们可以将Java记录定义为Spring Boot中的配置属性。例如,前面的示例可以重写为:
@ConstructorBinding
@ConfigurationProperties(prefix = "mail.credentials")
public record ImmutableCredentials(String authMethod, String username, String password) {
}