持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情
基于 Spring Framework v5.2.6.RELEASE
接上篇:Spring 源码阅读 37:postProcessBeanDefinitionRegistry 对 @Configuration 配置的解析和处理(2)
概述
之前的两篇文章介绍了 ConfigurationClassPostProcessor 后处理器的postProcessBeanDefinitionRegistry方法对配置类的处理,在处理完成之后,后处理器的postProcessBeanFactory方法还会被执行。本文开始分析postProcessBeanFactory方法对配置类执行了哪些工作。
处理过程
首先进入postProcessBeanFactory方法查看源码。
// org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanFactory
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
首先获取了当前 BeanFactory 容器的factoryId,然后判断postProcessBeanFactory方法是否已经执行过了,如果执行过了,则排出异常,确保这个方法不被重复执行。然后又判断了postProcessBeanDefinitionRegistry是不是被执行过了,如果没有被执行,则调用processConfigBeanDefinitions方法,这里是为了确保当前处理方法的业务流程在执行之前,processConfigBeanDefinitions方法已经被先执行过了。
以上的判断都执行完成之后,是主要流程的执行,其中的重点就是enhanceConfigurationClasses方法。
enhanceConfigurationClasses 方法
从方法的名称来看,这个方法是对配置类的增强。进入enhanceConfigurationClasses方法的源码。
我们先大概浏览一下这个方法的代码结构,大概可以分为两个大部分。
首先,创建了一个 Map 集合configBeanDefs,Key 是字符串类型,Value 是 AbstractBeanDefinition 类型,可以看出,这里面存放的是配置类的 BeanDefinition。下面紧跟的for循环中,会遍历容器中所有的 BeanDefinition,进行筛选,将符合条件的 BeanDefinition 放到configBeanDefs中,如果遍历完之后configBeanDefs还是空的,则方法直接返回。
然后,会通过下一个for循环对configBeanDefs中所有的 Value 进行遍历,对配置类进行增强。
下面我们就分为两部分进行分析。
配置类的筛选
首先是第一部分,筛选配置类的部分。
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
MethodMetadata methodMetadata = null;
if (beanDef instanceof AnnotatedBeanDefinition) {
methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
}
if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
// Configuration class (full or lite) or a configuration-derived @Bean method
// -> resolve bean class at this point...
AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
if (!abd.hasBeanClass()) {
try {
abd.resolveBeanClass(this.beanClassLoader);
}
catch (Throwable ex) {
throw new IllegalStateException(
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
if (!(beanDef instanceof AbstractBeanDefinition)) {
throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
}
else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
logger.info("Cannot enhance @Configuration bean definition '" + beanName +
"' since its singleton instance has been created too early. The typical cause " +
"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
"return type: Consider declaring such methods as 'static'.");
}
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
对当前遍历到的每一个 BeanDefinition,除了获取到 BeanDefinition 对象beanDef之外,还会获取configClassAttr。
configClassAttr是 BeanDefinition 对象中的一个属性值,属性名为org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass。这个属性是在执行后处理器的postProcessBeanDefinitionRegistry方i 可开开心心学习法时设置的,默认情况下是full。这个值其实就代表了@Configuration注解的proxyBeanMethods属性为默认值true。
除此之外, 还声明了一个 MethodMetadata 类型的变量methodMetadata,值暂时为空。
接着,是三个if语句块,先看第一个。
if (beanDef instanceof AnnotatedBeanDefinition) {
methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
}
这里判断了当前的 BeanDefinition 的类型是不是 AnnotatedBeanDefinition。如果是的话,则获取它的factoryMethodMetadata属性,作为methodMetadata的值。factoryMethodMetadata是它的工厂方法相关的信息,一般情况下是一个空值。
再看第二个if语句块。
if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
// Configuration class (full or lite) or a configuration-derived @Bean method
// -> resolve bean class at this point...
AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
if (!abd.hasBeanClass()) {
try {
abd.resolveBeanClass(this.beanClassLoader);
}
catch (Throwable ex) {
throw new IllegalStateException(
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
根据前面的条件可以知道,这里的判断条件是成立的。在if语句块中,会判断 BeanDefinition 对应的类型是否存在,如果不存在,则通过类加载器加载。这一部比较简单。
下面看第三个if语句块。
if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
if (!(beanDef instanceof AbstractBeanDefinition)) {
throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
}
else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
logger.info("Cannot enhance @Configuration bean definition '" + beanName +
"' since its singleton instance has been created too early. The typical cause " +
"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
"return type: Consider declaring such methods as 'static'.");
}
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
这里会判断configClassAttr的属性值是不是full,这个属性值前文已经介绍过了。如果是的话,则将它添加到configBeanDefs中,这里的 Key 是 Bean 的名称,值是被转换为 AbstractBeanDefinition 类型的当前的 BeanDefinition。
最后,当for循环执行完之后,configBeanDefs集合仍然为空,说明没有配置类需要进行增强处理,方法直接返回。代码如下:
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
return;
}
反之,如果configBeanDefs中是有元素的,那么则开始后续的步骤,也就是对这些配置类进行增强处理。
总结
本文分析了postProcessBeanFactory处理方法调用的enhanceConfigurationClasses方法对配置类进行增强处理的前半部分流程,也就是如何从容器中找到需要进行增强处理的配置类的 BeanDefinition。下一篇讲分析后续的流程,也就是如何对这些配置类进行增强处理。