关于@ConfigurationProperties
曾提过一个issue,涉及SpringBoot 2.2.1之前版本
Setting ignoreInvalidFields=true on @ConfigurationProperties causes unknown fields to be ignored as well
@ConfigurationProperties
主要作用就是将prefix
属性指定的前缀配置项的值绑定到这个Bean上,默认情况下需要和@Component
或者@Configuration
一起使用才能生效.
实现原理参见另一篇博客: @EnableConfigurationProperties @ConfigurationProperties @ConfigurationPropertiesScan
本文主要讲解@ConfigurationProperties
注解中的几个属性作用. 及两种使用方式:
- 使用在类上
- 使用在方法上
@ConfigurationProperties中的几个属性作用
public @interface ConfigurationProperties {
@AliasFor("prefix")
String value() default "";
@AliasFor("value")
String prefix() default "";
boolean ignoreInvalidFields() default false;
boolean ignoreUnknownFields() default true;
}
value
和prefix
功能相同,比较容易理解就是将指定的前缀属性绑定到这个Bean上的属性。
ignoreInvalidFields
:默认false
表示绑定到此对象时应忽略无效字段。指示绑定到此对象时应忽略无效字段。一般是字段类型错误(或无法强制转换为正确类型),例如:实体类中定义的可能是一个Boolean类型,但是配置项的值却是日期。则这个时候会报错.
ignoreUnknownFields
: 默认true
,表示绑定到此对象时应忽略实体类中不存在的字段。例如配置项中可能有一个同样前缀的配置,但是实体类中没有对应的属性.
使用在类上
prefix示例
首先完成一个基础demo,在springboot的配置文件中(默认application.properties)编写对应的配置项值。
datasource.config.read-only=false
datasource.config.url=localhost
datasource.config.username=bruce
datasource.config.pwd=123456
编写实体类
@Component
@ConfigurationProperties(prefix = "datasource.config")
public class DataSourceProperties {
private String url;
private String pwd;
private String username;
private Boolean readOnly;
// Setter/Getter
}
使用绑定后的属性值
@SpringBootTest
class Demo1ApplicationTests {
@Autowired
private DataSourceProperties dataSourceProperties;
@Test
void contextLoads() {
System.out.println(dataSourceProperties);
}
}
打印结果如下,正确绑定了属性值.
ignoreInvalidFields示例:
将application.properties中的配置修改为如下的值
datasource.config.read-only=aa
......其他属性不变
默认由于 “aa” 无法转为Boolean类型,所以报错
在@ConfigurationProperties(prefix = "datasource.config")
添加**ignoreInvalidFields=true
**
@ConfigurationProperties(prefix = "datasource.config", ignoreInvalidFields=true)
此时执行程序可以正常执行
ignoreUnknownFields示例:
在application.properties中多添加一个相同前缀的配置,但实际上DataSourceProperties中并不存在同名的属性
datasource.config.poolSize=12
默认不会报错
但是在@ConfigurationProperties(prefix = "datasource.config")
添加**ignoreUnknownFields=false
**
@ConfigurationProperties(prefix = "datasource.config", ignoreUnknownFields=false)
此时执行程序则会报错
一般情况下只需要指定@ConfigurationProperties
注解的prefix属性即可,其它注解属性保持默认值还是比较合理的。
使用在方法上
org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration.Hikari
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(HikariDataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource",
matchIfMissing = true)
static class Hikari {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.hikari")
HikariDataSource dataSource(DataSourceProperties properties) {
HikariDataSource dataSource = createDataSource(properties, HikariDataSource.class);
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName());
}
return dataSource;
}
}
当方法返回对象之后,springboot会将指定前缀的属性值再绑定到对象属性上。也就是配置项优先级高于代码赋值。
原理分析:
spring在解析类时,会将所有带@Bean
方法包装成ConfigurationClassBeanDefinition
注册到spring中,ConfigurationClassBeanDefinition
包含了SimpleMethodMetadata
信息,用于反射调用方法,SimpleMethodMetadata
里则存有方法上的注解信息.
注册Method
的BeanDefinition
的源码:org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass
方法返回值属性绑定的流程:
当调用方法创建对象之后,会经过ConfigurationPropertiesBindingPostProcessor#postProcessBeforeInitialization
方法,调用ConfigurationPropertiesBean#get(ApplicationContext applicationContext, Object bean, String beanName)
方法,从spring中获取原先注册的ConfigurationClassBeanDefinition
,从中拿到Method
,判断方法上是否有@ConfigurationProperties
注解。如果没有,返回null,不需要绑定属性值。如果有则创建ConfigurationPropertiesBean
,调用绑定属性值的方法。最后返回Bean对象。
相关源码如下: