@ConfigurationProperties 注解用于将 bean 中的成员属性与配置文件中的属性进行绑定
可以注解在类上或方法上
类上注解 @Component 与 @ConfigurationProperties 即可
例如 yaml 配置文件中有如下配置:
test-bean:
ipaddress: 127.0.0.1
port: 8080
有如下 TestBean:
@Data
@Component
@ConfigurationProperties(prefix = "test-bean")
// @ConfigurationProperties("test-bean") // 默认即为 prefix 属性指定
public class TestBean {
private String ipAddress;
private int port;
}
@ConfigurationProperties 注解的 prefix 属性用于指定绑定配置中的属性
可以在启动类中获取 applicationContext 之后获取 bean 来查看效果:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);
TestBean bean = applicationContext.getBean(TestBean.class);
System.out.println(bean);
// 输出:TestBean(ipAddress=192.168.100.100, port=8088)
}
}
在 idea 中,自定义的 bean 注解 @ConfigurationProperties 可能会有以下错误
如果不想见到可以引入下面的依赖,即可解决
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
dependency>
配置类中写一个返回该 bean 的方法,并在方法上注解 @Bean 与 @ConfigurationProperties 即可
以 Druid 连接池中的 DruidDataSource 为例
注意导入 druid 依赖而非 druid-spring-boot-starter
yaml 配置如下:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
我们将启动类作为配置类来测试:
@SpringBootApplication
public class Application {
@Bean
@ConfigurationProperties(prefix = "datasource")
public DruidDataSource druidDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("noting");
return dataSource;
}
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);
DruidDataSource dataSource = applicationContext.getBean(DruidDataSource.class);
System.out.println(dataSource.getDriverClassName());
// 输出:com.mysql.cj.jdbc.Driver
}
}
注意 @Bean 方法里对属性 set 不会影响配置文件中的配置
如上例中,方法内调用了 setDriverClassName 方法,但输出的依然是 yaml 配置中的属性值
可以把 @Bean 方法中的 set 方法给定的值当作默认配置,而 yaml 文件中的是最终配置
@EnableConfigurationProperties 注解在配置类或启动类上,用于指定开启绑定的类,多个类用数组
其效果与 bean 上注解 @Component 相同,但两者不能同时对一个 bean 生效,会因为找到两个相同的 bean 而报错
@EnableConfigurationProperties 添加的类,类上必须有 @ConfigurationProperties 注解
@EnableConfigurationProperties 与 @Bean 注解的方法不会产生关联
TestBean 示例如下:
@Data
//@Component
@ConfigurationProperties(prefix = "test-bean")
public class TestBean {
// ...
}
启动类:
@SpringBootApplication
@EnableConfigurationProperties({TestBean.class})
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);
TestBean bean = applicationContext.getBean(TestBean.class);
System.out.println(bean);
}
}
松散绑定(或宽松绑定),指绑定属性时不必严格与属性名一致
在 @ConfigurationProperties 注解中,可以添加任意的中划线 “-”,但不能中划线开头,不能包含大写字母,事实上只能使用小写字母和中划线
在 yaml 配置文件中,属性名可以添加任意的 中划线 “-”,下划线 “_”,空格,不影响绑定的匹配
示例下:
TestBean:
@Component
@ConfigurationProperties(prefix = "test-bean") // 可添加任意的 '-',但不可符号开头,也不可含大写字母
@Data
public class TestBean {
private String ipAddress; // 变量名也可添加 '_'
}
yaml:
# 以下均可正常匹配
testbean:
ip-address: 192.168.0.101 # 烤肉串格式(官方推荐)
ip_address: 192.168.0.102 # 下划线格式
IP_ADDRESS: 192.168.0.103 # 常量格式,大写与下划线
"ip address": 192.168.0.104 # 空格或双引号也是可以的
-_iPa_d d-- Re ss: 192.168.0.105 # 乱七八糟,只要字母可匹配就能生效
官方推荐的格式是烤肉串格式,如果存在多个可匹配的属性时,只有烤肉串格式的生效
另外,据黑马李老师所讲,@Value 注入属性值时,不支持松散匹配
但我个人测试时是可以的,测试类如下:
@SpringBootTest
class ApplicationTests {
@Value("${mytest.message}")
private String message;
@Test
void contextLoads() {
System.out.println(message);
// 输出:Hello world!!
}
}
yaml文件如下:
my-test:
_MESSAGE-: Hello world!!
@Value 中只要不含 中划线和小写字母以外 的符号即可
Duration 表示一段时间,如 3分钟,5小时
DataSize 表示文件大小,如 10B,5MB
这样的属性在配置的时候可以指定单位
如下:
@Component
@ConfigurationProperties(prefix = "test-bean")
@Data
public class TestBean {
// 指定默认时间单位,未设置则为毫秒 ms
@DurationUnit(ChronoUnit.SECONDS)
private Duration serverTimeout;
// 指定文件单位,未设置则为字节 B
@DataSizeUnit(DataUnit.KILOBYTES)
private DataSize dataSize;
}
yaml 配置文件:
test-bean:
server-timeout: 3ms #只支持天以内的单位:ms, s, m, h, d
data-size: 10B #必须大写:B, KB, MB, GB, TB
举例,端口号的设定范围是 0 ~ 65535,我们希望启动时对配置进行校验
validation-api 提供接口,而 hibernate-validator 提供实现
<dependency>
<groupId>javax.validationgroupId>
<artifactId>validation-apiartifactId>
dependency>
<dependency>
<groupId>org.hibernate.validatorgroupId>
<artifactId>hibernate-validatorartifactId>
dependency>
示例如下:
@Data
@Component
@Validated
@ConfigurationProperties(prefix = "test-bean")
public class TestBean {
@Max(value = 65535, message = "最大端口号为 65535")
@Min(value = 0, message = "最小端口号为 0")
private int port;
}
在 javax.validation.constraints 包内还有其它可以自定义的规则,可以自己研究下
yaml 文件中配置纯数字可能会导致结果不合预期,如下示例:
yaml 配置:
my-test:
password: 012345
测试类:
@SpringBootTest
class ApplicationTests {
@Value("${my-test.password}")
private String password;
@Test
void contextLoads() {
System.out.println(password);
// 输出:5349
}
}
可以发现 password 的值配置的是 012345,结果却变成了5349
这是因为 012345 触发了八进制的转换格式
0 开头且所以数字小于8,便会被当作八进制转为十进制,然后被注入到属性
同样还有,0b 开头为二进制,0x 开头为十六进制
如 0b_0101_0101 和 0x3f3f3f3f
建议字符串类型的属性用双引号括住比较好,尤其密码类的难以排查原因