Spring5源码解析5-ConfigurationClassPostProcessor (上)
接上回,我们讲到了refresh()
方法中的invokebeanfactorypostprocessors(beanfactory)
方法主要在执行beanfactorypostprocessor
和其子接口beandefinitionregistrypostprocessor
的方法。
在创建annotationconfigapplicationcontext
对象时spring就添加了一个非常重要的beanfactorypostprocessor
接口实现类:configurationclasspostprocessor
。注意,这里说的添加只是添加到容器的beandefinitionmap
中,还没有创建真正的实例bean。
简单回顾一下configurationclasspostprocessor
是在什么时候被添加到容器中的:在annotationconfigapplicationcontext
的无参构造器中创建annotatedbeandefinitionreader
对象时会向传入的beandefinitionregistry
中注册解析注解配置类相关的processors的beandefinition
,configurationclasspostprocessor
就是在此处被添加到容器中的。
configurationclasspostprocessor
先看一些configurationclasspostprocessor
的继承体系:
configurationclasspostprocessor
实现了beandefinitionregistrypostprocessor
接口,也就拥有了在spring容器启动时,往容器中注册beandefinition
的能力。
我们知道,configurationclasspostprocessor#postprocessbeandefinitionregistry
方法是在refresh();
方法中的invokebeanfactorypostprocessors(beanfactory);
中被执行的,下面我们就一起来看一下该方法。
configurationclasspostprocessor#postprocessbeandefinitionregistry
@override public void postprocessbeandefinitionregistry(beandefinitionregistry registry) { int registryid = system.identityhashcode(registry); if (this.registriespostprocessed.contains(registryid)) { throw new illegalstateexception( "postprocessbeandefinitionregistry already called on this post-processor against " + registry); } if (this.factoriespostprocessed.contains(registryid)) { throw new illegalstateexception( "postprocessbeanfactory already called on this post-processor against " + registry); } this.registriespostprocessed.add(registryid); processconfigbeandefinitions(registry); }
主要的逻辑在processconfigbeandefinitions(registry);
中,点开源码:
public void processconfigbeandefinitions(beandefinitionregistry registry) { list<beandefinitionholder> configcandidates = new arraylist<>(); //获取所有的beandefinitionname string[] candidatenames = registry.getbeandefinitionnames(); for (string beanname : candidatenames) { beandefinition beandef = registry.getbeandefinition(beanname); // https://docs.spring.io/spring/docs/5.1.8.release/spring-framework-reference/core.html#beans-java-basic-concepts // full @configuration vs “lite” @bean mode if (configurationclassutils.isfullconfigurationclass(beandef) || configurationclassutils.isliteconfigurationclass(beandef)) { if (logger.isdebugenabled()) { logger.debug("bean definition has already been processed as a configuration class: " + beandef); } } // 校验是否为配置类 // 配置类分为两种 full @configuration vs “lite” @bean mode // 校验之后在 beandefinition 中添加标志属性 // 如果满足条件则加入到configcandidates else if (configurationclassutils.checkconfigurationclasscandidate(beandef, this.metadatareaderfactory)) { // 如果是配置类,就放到 configcandidates 变量中 configcandidates.add(new beandefinitionholder(beandef, beanname)); } } // return immediately if no @configuration classes were found if (configcandidates.isempty()) { return; } // sort by previously determined @order value, if applicable configcandidates.sort((bd1, bd2) -> { int i1 = configurationclassutils.getorder(bd1.getbeandefinition()); int i2 = configurationclassutils.getorder(bd2.getbeandefinition()); return integer.compare(i1, i2); }); // detect any custom bean name generation strategy supplied through the enclosing application context singletonbeanregistry sbr = null; // 传入的 registry 是 defaultlistablebeanfactory if (registry instanceof singletonbeanregistry) { sbr = (singletonbeanregistry) registry; if (!this.localbeannamegeneratorset) { //获取自定义beannamegenerator,一般情况下为空 beannamegenerator generator = (beannamegenerator) sbr.getsingleton(configuration_bean_name_generator); if (generator != null) { this.componentscanbeannamegenerator = generator; this.importbeannamegenerator = generator; } } } if (this.environment == null) { this.environment = new standardenvironment(); } // parse each @configuration class // new configurationclassparser,用来解析 @configuration 类 configurationclassparser parser = new configurationclassparser( this.metadatareaderfactory, this.problemreporter, this.environment, this.resourceloader, this.componentscanbeannamegenerator, registry); // 将 configcandidates 转成 set candidates , 去重 set<beandefinitionholder> candidates = new linkedhashset<>(configcandidates); set<configurationclass> alreadyparsed = new hashset<>(configcandidates.size()); do { // 解析配置类 parser.parse(candidates); parser.validate(); set<configurationclass> configclasses = new linkedhashset<>(parser.getconfigurationclasses()); configclasses.removeall(alreadyparsed); // read the model and create bean definitions based on its content if (this.reader == null) { this.reader = new configurationclassbeandefinitionreader( registry, this.sourceextractor, this.resourceloader, this.environment, this.importbeannamegenerator, parser.getimportregistry()); } // import类,@bean,@importresource 转化为 beandefinition this.reader.loadbeandefinitions(configclasses); alreadyparsed.addall(configclasses); candidates.clear(); // 再获取一下容器中beandefinition的数据,如果发现数量增加了,说明有新的beandefinition被注册了 if (registry.getbeandefinitioncount() > candidatenames.length) { string[] newcandidatenames = registry.getbeandefinitionnames(); set<string> oldcandidatenames = new hashset<>(arrays.aslist(candidatenames)); set<string> alreadyparsedclasses = new hashset<>(); for (configurationclass configurationclass : alreadyparsed) { alreadyparsedclasses.add(configurationclass.getmetadata().getclassname()); } for (string candidatename : newcandidatenames) { if (!oldcandidatenames.contains(candidatename)) { beandefinition bd = registry.getbeandefinition(candidatename); if (configurationclassutils.checkconfigurationclasscandidate(bd, this.metadatareaderfactory) && !alreadyparsedclasses.contains(bd.getbeanclassname())) { candidates.add(new beandefinitionholder(bd, candidatename)); } } } candidatenames = newcandidatenames; } } while (!candidates.isempty()); // register the importregistry as a bean in order to support importaware @configuration classes if (sbr != null && !sbr.containssingleton(import_registry_bean_name)) { sbr.registersingleton(import_registry_bean_name, parser.getimportregistry()); } if (this.metadatareaderfactory instanceof cachingmetadatareaderfactory) { // clear cache in externally provided metadatareaderfactory; this is a no-op // for a shared cache since it'll be cleared by the applicationcontext. ((cachingmetadatareaderfactory) this.metadatareaderfactory).clearcache(); } }
获取所有的beandefinitionnames,然后循环这个数组,判断其是否为配置类。
前5个是spring注册的内置processor,最后一个是传入给annotationconfigapplicationcontext
的配置类appconfig.class
。
在spring中存在两种configurationclass,一种是fullconfigurationclass
另一种是liteconfigurationclass
。关于这两者的区别,可以参看笔者文章之前关于full @configuration 和 lite @bean mode的文章。
configurationclassutils#checkconfigurationclasscandidate
方法内部就是在判断属于哪种配置类,并在beandefinition
中标记判断结果。其具体的判断逻辑如下:
public static boolean isfullconfigurationcandidate(annotationmetadata metadata) { return metadata.isannotated(configuration.class.getname()); } private static final set<string> candidateindicators = new hashset<>(8); static { candidateindicators.add(component.class.getname()); candidateindicators.add(componentscan.class.getname()); candidateindicators.add(import.class.getname()); candidateindicators.add(importresource.class.getname()); } public static boolean isliteconfigurationcandidate(annotationmetadata metadata) { // do not consider an interface or an annotation... if (metadata.isinterface()) { return false; } // any of the typical annotations found? for (string indicator : candidateindicators) { if (metadata.isannotated(indicator)) { return true; } } // finally, let's look for @bean methods... try { return metadata.hasannotatedmethods(bean.class.getname()); } catch (throwable ex) { if (logger.isdebugenabled()) { logger.debug("failed to introspect @bean methods on class [" + metadata.getclassname() + "]: " + ex); } return false; } }
判断configcandidates
变量中存放的
配置类是否为空,如果不为空,则对其进行排序。
创建configurationclassparser
对象,用于解析@configuration
类,完成包的扫描、beandefinition
的注册。主要通过执行parser.parse(candidates);
方法来完成。
执行parser.parse(candidates)
方法前 :
执行parser.parse(candidates)
方法后 :
解析完配置类之后,紧接着又执行了this.reader.loadbeandefinitions(configclasses);
方法。这个方法主要是用来处理import类
、@bean
和@importresource
注解。关于这两个方法的具体细节,我们下次再讲。
最后又加了入了对importaware
接口支持所需要的bean。
// register the importregistry as a bean in order to support importaware @configuration classes if (sbr != null && !sbr.containssingleton(import_registry_bean_name)) { sbr.registersingleton(import_registry_bean_name, parser.getimportregistry()); }
关于对importaware
接口的使用,我们也下次再讲。
未完待续......
源码学习笔记:https://github.com/shenjianeng/spring-code-study
欢迎各位关注公众号,大家一起学习成长。
上一篇: 烟台人气最旺餐厅排行 为了吃上你一口,驱车50公里也值得
下一篇: 第1次作业-Numpy练习
推荐阅读
-
spring5 源码深度解析----- 事务的回滚和提交(100%理解事务)
-
Spring5源码解析5-ConfigurationClassPostProcessor (上)
-
spring5 源码深度解析----- AOP代理的生成
-
Spring5源码解析4-refresh方法之invokeBeanFactoryPostProcessors
-
spring5 源码深度解析----- 被面试官给虐懵了,竟然是因为我不懂@Configuration配置类及@Bean的原理
-
spring5 源码深度解析-----ApplicationContext容器refresh过程
-
spring源码深度解析— IOC 之 默认标签解析(上)
-
Spring5源码解析6-ConfigurationClassParser 解析配置类
-
Spring5源码 - 08 BeanFactory和FactoryBean 源码解析 & 使用场景
-
Spring5源码分析(二):Spring IOC 源码解析