基于 Spring Framework v5.2.6.RELEASE
接上篇:Spring 源码阅读 37:postProcessBeanDefinitionRegistry 对 @Configuration 配置的解析和处理(2)
概述
之前的两篇文章介绍了 ConfigurationClassPostProcessor 后处理器的postProcessBeanDefinitionRegistry
方法对配置类的处理,在处理完成之后,后处理器的postProcessBeanFactory
方法还会被执行。本文开始分析postProcessBeanFactory
方法对配置类执行了哪些工作。
处理过程
首先进入postProcessBeanFactory方法查看源码。
// org.springframework.context.annotation.ConfigurationClassPostProcessor#postProcessBeanFactorypublicvoidpostProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory) { intfactoryId=System.identityHashCode(beanFactory); if (this.factoriesPostProcessed.contains(factoryId)) { thrownewIllegalStateException( "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(newImportAwareBeanPostProcessor(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 (StringbeanName : beanFactory.getBeanDefinitionNames()) { BeanDefinitionbeanDef=beanFactory.getBeanDefinition(beanName); ObjectconfigClassAttr=beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE); MethodMetadatamethodMetadata=null; if (beanDefinstanceofAnnotatedBeanDefinition) { methodMetadata= ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata(); } if ((configClassAttr!=null||methodMetadata!=null) &&beanDefinstanceofAbstractBeanDefinition) { // Configuration class (full or lite) or a configuration-derived @Bean method// -> resolve bean class at this point...AbstractBeanDefinitionabd= (AbstractBeanDefinition) beanDef; if (!abd.hasBeanClass()) { try { abd.resolveBeanClass(this.beanClassLoader); } catch (Throwableex) { thrownewIllegalStateException( "Cannot load configuration class: "+beanDef.getBeanClassName(), ex); } } } if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) { if (!(beanDefinstanceofAbstractBeanDefinition)) { thrownewBeanDefinitionStoreException("Cannot enhance @Configuration bean definition '"+beanName+"' since it is not stored in an AbstractBeanDefinition subclass"); } elseif (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 (beanDefinstanceofAnnotatedBeanDefinition) { methodMetadata= ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata(); }
这里判断了当前的 BeanDefinition 的类型是不是 AnnotatedBeanDefinition。如果是的话,则获取它的factoryMethodMetadata
属性,作为methodMetadata
的值。factoryMethodMetadata
是它的工厂方法相关的信息,一般情况下是一个空值。
再看第二个if
语句块。
if ((configClassAttr!=null||methodMetadata!=null) &&beanDefinstanceofAbstractBeanDefinition) { // Configuration class (full or lite) or a configuration-derived @Bean method// -> resolve bean class at this point...AbstractBeanDefinitionabd= (AbstractBeanDefinition) beanDef; if (!abd.hasBeanClass()) { try { abd.resolveBeanClass(this.beanClassLoader); } catch (Throwableex) { thrownewIllegalStateException( "Cannot load configuration class: "+beanDef.getBeanClassName(), ex); } } }
根据前面的条件可以知道,这里的判断条件是成立的。在if
语句块中,会判断 BeanDefinition 对应的类型是否存在,如果不存在,则通过类加载器加载。这一部比较简单。
下面看第三个if语句块。
if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) { if (!(beanDefinstanceofAbstractBeanDefinition)) { thrownewBeanDefinitionStoreException("Cannot enhance @Configuration bean definition '"+beanName+"' since it is not stored in an AbstractBeanDefinition subclass"); } elseif (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 immediatelyreturn; }
反之,如果configBeanDefs中是有元素的,那么则开始后续的步骤,也就是对这些配置类进行增强处理。
总结
本文分析了postProcessBeanFactory
处理方法调用的enhanceConfigurationClasses
方法对配置类进行增强处理的前半部分流程,也就是如何从容器中找到需要进行增强处理的配置类的 BeanDefinition。下一篇讲分析后续的流程,也就是如何对这些配置类进行增强处理。