我们在之前的文章中简单的说了一下SpringBoot对于默认的配置文件的解析过程,在这一篇文章中我们再简单的分析一下SpringBoot是怎么将解析到的配置属性信息设置到相应的Bean上的。既然是用SpringBoot的属性配置方式,那么我们在这里会在对应的类上加上ConfigurationProperties和Component(或是和Component相同功能的)注解。我们定义的Bean如下:
@Component
@ConfigurationProperties(prefix ="person.info")
public class PersonInfoDomain {
/**
* 用户名
*/
private String userName;
}
配置文件如下:
其内容依次如下:
person.info.user-name=lisi
person:
info:
user-name: zhangzhang
person.info.user-name=zhangsan
person:
info:
user-name: lilisisi
首先问一个问题,如果是你来实现这样的功能的话,你会在什么时机来进行属性值设置的功能呢?在创建Bean的时候进行属性的设置应该是一个比较合适的时机吧?Spring也是这样做的。在Spring中提供了各种不同功能的接口来让我们在Bean创建的过程中做一些不同功能的扩展,我们先称为”生命周期”的接口(可以在这里进行查看:Spring Bean的生命周期小析(一) Spring Bean的生命周期小析(二)),在Spring在有这样一个类:AbstractAutowireCapableBeanFactory这个类主要的一个功能是串联Spring的生命周期。我们先看一下这个类中的这个方法:applyBeanPostProcessorsBeforeInitialization(不要问我为什么知道这个方法。。。放一下调用链的截图)
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
//这里的getBeanPostProcessors()这个方法获取到的是Spring 容器中实现BeanPostProcessor接口的Bean 在这个Bean中有一个Bean叫ConfigurationPropertiesBindingPostProcessor 从这个Bean的名字我们可以感觉这个Bean应该是和ConfigurationProperties相关的类,而事实也确是如此 其他的我们先不说了,放一下SpringBoot中内置的一些BeanPostProcessor 的Bean,我们直接进入到 ConfigurationPropertiesBindingPostProcessor 这个类中
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
//获取类上的ConfigurationProperties注解 用AnnotationUtils来对类上的注解进行处理是很方便,有兴趣的可以看一下AnnotationUtils中的方法的源码实现
ConfigurationProperties annotation = AnnotationUtils
.findAnnotation(bean.getClass(), ConfigurationProperties.class);
//如果类上有ConfigurationProperties 注解
if (annotation != null) {
//主要处理方法
postProcessBeforeInitialization(bean, beanName, annotation);
}
//方法上的ConfigurationProperties注解
annotation = this.beans.findFactoryAnnotation(beanName,
ConfigurationProperties.class);
if (annotation != null) {
postProcessBeforeInitialization(bean, beanName, annotation);
}
return bean;
}
org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor#postProcessBeforeInitialization
private void postProcessBeforeInitialization(Object bean, String beanName,
ConfigurationProperties annotation) {
//我们需要设置属性的目标bean
Object target = bean;
//新建一个PropertiesConfigurationFactory类 这个类来完成属性的赋值的工作
PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>(
target);
//propertySources 1)
factory.setPropertySources(this.propertySources);
//验证器
factory.setValidator(determineValidator(bean));
//转换服务
factory.setConversionService(this.conversionService == null
? getDefaultConversionService() : this.conversionService);
if (annotation != null) {
//类上 ConfigurationProperties注解的信息
factory.setIgnoreInvalidFields(annotation.ignoreInvalidFields());
factory.setIgnoreUnknownFields(annotation.ignoreUnknownFields());
factory.setExceptionIfInvalid(annotation.exceptionIfInvalid());
factory.setIgnoreNestedProperties(annotation.ignoreNestedProperties());
//属性前缀
if (StringUtils.hasLength(annotation.prefix())) {
factory.setTargetName(annotation.prefix());
}
}
try {
//主要方法
factory.bindPropertiesToTarget();
}
}
对于1)处的PropertySources我们应该不陌生了,前面我们一直在提到这个类。我们看一下这个PropertySources是在什么时候进行赋值的。在ConfigurationPropertiesBindingPostProcessor中有一个这样的方法afterPropertiesSet:
public void afterPropertiesSet() throws Exception {
if (this.propertySources == null) {
//寻找PropertySources
this.propertySources = deducePropertySources();
}
//validator的赋值
if (this.validator == null) {
this.validator = getOptionalBean(VALIDATOR_BEAN_NAME, Validator.class);
}
//转换服务
if (this.conversionService == null) {
this.conversionService = getOptionalBean(
ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME,
ConversionService.class);
}
}
private PropertySources deducePropertySources() {
//从Spring 容器中获取 PropertySourcesPlaceholderConfigurer
PropertySourcesPlaceholderConfigurer configurer = getSinglePropertySourcesPlaceholderConfigurer();
if (configurer != null) {
//configurer.getAppliedPropertySources() 这里获取到的就是我们之前一直提到的MutablePropertySources
return new FlatPropertySources(configurer.getAppliedPropertySources());
}
//如果Spring 容器中 没有PropertySourcesPlaceholderConfigurer的话 则从ConfigurableEnvironment中获取
if (this.environment instanceof ConfigurableEnvironment) {
MutablePropertySources propertySources = ((ConfigurableEnvironment) this.environment)
.getPropertySources();
return new FlatPropertySources(propertySources);
}
//还获取不到的话,则新建一个MutablePropertySources
return new MutablePropertySources();
}
private PropertySourcesPlaceholderConfigurer getSinglePropertySourcesPlaceholderConfigurer() {
if (this.beanFactory instanceof ListableBeanFactory) {
//从Spring 容器中获取 PropertySourcesPlaceholderConfigurer
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) this.beanFactory;
Map<String, PropertySourcesPlaceholderConfigurer> beans = listableBeanFactory
.getBeansOfType(PropertySourcesPlaceholderConfigurer.class, false,
false);
if (beans.size() == 1) {
return beans.values().iterator().next();
}
//如果有多于一个存在的话,则返回null
if (beans.size() > 1 && logger.isWarnEnabled()) {
}
}
return null;
}
OK,我们进入到PropertiesConfigurationFactory看一下factory.bindPropertiesToTarget();这个方法的内容:
public void bindPropertiesToTarget() throws BindException {
//propertySources不能为null
Assert.state(this.propertySources != null, "PropertySources should not be null");
try {
this.hasBeenBound = true;
doBindPropertiesToTarget();
}
}
private void doBindPropertiesToTarget() throws BindException {
//targetName PropertiesConfigurationFactory注解上的前缀值
//target 目标bean
RelaxedDataBinder dataBinder = (this.targetName != null
? new RelaxedDataBinder(this.target, this.targetName)
: new RelaxedDataBinder(this.target));
//校验器
if (this.validator != null
&& this.validator.supports(dataBinder.getTarget().getClass())) {
dataBinder.setValidator(this.validator);
}
//转换服务
if (this.conversionService != null) {
dataBinder.setConversionService(this.conversionService);
}
//集合的最大值
dataBinder.setAutoGrowCollectionLimit(Integer.MAX_VALUE);
dataBinder.setIgnoreNestedProperties(this.ignoreNestedProperties);
dataBinder.setIgnoreInvalidFields(this.ignoreInvalidFields);
dataBinder.setIgnoreUnknownFields(this.ignoreUnknownFields);
//自定义Binder 这里是一个空实现
customizeBinder(dataBinder);
//下面这两段代码是获取 Spring支持的配置的名字 支持格式超出你的想象 可以调试自己看一下
Iterable<String> relaxedTargetNames = getRelaxedTargetNames();
Set<String> names = getNames(relaxedTargetNames);
//获取PropertyValues 重点要分析的
PropertyValues propertyValues = getPropertySourcesPropertyValues(names,
relaxedTargetNames);
//属性值的绑定工作
dataBinder.bind(propertyValues);
if (this.validator != null) {
//属性值的校验
dataBinder.validate();
}
checkForBindingErrors(dataBinder);
}