先前几篇都是概念的讲解:回顾下java
- BeanDefinition 是物料
- Bean是成品
- BeanFactory是仓库,存储物料与成品
- ApplicationContext初始化搜集物料入库,触发生产线,取出物料生产Bean
本文研究springboot环境下,ApplicationContext的初始化, 可能是处理注解形式的Bean.spring
重要组件
1.PostProcessorRegistrationDelegate: 代理执行post processors的工具类缓存
postProcessor分为两种:springboot
- BeanFactoryPostProcessor: 发生在BeanDefinition搜集入库阶段
- BeanPostProcessor: 发生在BeanDefintion生成Bean阶段
BeanFactoryPostProcessor细分又分为两种:工具
- BeanDefinitionRegistryPostProcessor:继承BeanFactoryPostProcessor接口。其postProcessBeanDefinitionRegistry接口方法,具备注册更多Bean的语义。
- BeanFactoryPostProcessor:偏向于修改的语义。
2.ConfigurationClass: 这个类要理解, 表示的是配置类,是对一个具备配置语义的BeanDefinition的封装. 怎么理解这个呢. 我认为能够理解为一个xml文件. 记得一开始使用spring的时候, 须要在xml中配置bean.
post
ConfigurationClass语义:代理
- 一个ConfigurationClass 能够看作一个xml文件. 表明注解: @Configuration
- 一个ConfigurationClass 中能够定义Bean. 相似一个xml中能够定义Bean信息. 表明注解@Bean
- 一个ConfigurationClass 能够引入其余ConfigurationClass, 相似xml文件中会引入其余xml文件. 表明注解:@Import,@ComponentScan等
那么,怎么判断他是一个ConfigurationClass呢?看下面code
3.ConfigurationClassUtils: ConfigurationClass工具类cdn
checkConfigurationClassCandidate()方法: 先取出BeanDefinition的注解信息.xml
- 判断是不是full ConfigurationClass . 判断依据是是否被@Configuration注解标识,若是是必定是ConfigurationClass
- 判断是不是isLiteConfigurationCandidate, 判断依据是否被@Component,@ComponentScan,@Import,@ImportResource注解标识.
或者有@Bean标识的方法
总的来讲是看其是否能够输出Bean。判断其是否属于一个ConfigurationClass
4.ConfigurationClassPostProcessor:属于一种post processor. 实现了BeanDefinitionRegistryPostProcessor,间接实现了BeanFactoryPostProcessor. 因此具备 注册,与修改的双重功能.主要工做就是处理ConfigurationClass
5.ConfigurationClassParser: ConfigurationClass解析器.可以解析出项目中的ConfigurationClass. (类比能找到项目中全部的配置了Bean的xml)
6.ConfigurationClassBeanDefinitionReader: BeanDefintion读取器, 从ConfigurationClass中读取里面的Bean定义(类比可以从XML中读出Bean)
搜集入库:
建议配合源代码阅读
BeanDefintion的搜集发生在refresh()初始化方法中invokeBeanFactoryPostProcessors(beanFactory)阶段,执行BeanFactoryPostProcessor.

ApplicationContext委托PostProcessorRegistrationDelegate工具类执行post processors.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()方法执行全部BeanFactoryPostProcessor

invokeBeanFactoryPostProcessors:大致分为两步
- 首先执行BeanDefinitionRegistryPostProcessor. 调用其postProcessBeanDefinitionRegistry注册BeanDefinition
- 而后执行BeanFactoryPostProcessor 调用postProcessBeanFactory 提供修改BeanDefinition功能.
ConfigurationClassPostProcessor做为一个BeanDefinitionRegistryPostProcessor. 首先被执行.其processConfigBeanDefinitions方法:是收集BeanDefinition的开始的地方.
ConfigurationClassPostProcessor收集步骤:
- 从仓库中找出ConfigurationClass, 由于是初期, 因此库中只有springboot项目的启动文件这个ConfigurationClass. 此ConfigurationClass也能够看作是顶级ConfigurationClass ,就类型顶级xml文件, 去关联其余xml同样. 启动文件ConfigurationClass 做为一个入口存在.
- 建立一个ConfigurationClassParser准备解析ConfigurationClass.
- 调用
**ConfigurationClassParser.parse()**
解析刚找到的ConfigurationClass. 经过此入口.把全部须要ConfigurationClass找到. 就相似.经过一个xml文件把其关联的全部xml找到同样. 类比理解.
- 建立一个
**ConfigurationClassBeanDefinitionReader.loadBeanDefinitions() **
从找到的全部ConfigurationClass中. 遍历读取每一个ConfigurationClass中的Bean定义.
分支解析:
第三步ConfigurationClassParser.parse()分支: 目的找到全部须要的ConfigurationClass.(理解为找到xml文件)
此分支又大致分为2部分:
- parse():processConfigurationClass()-->doProcessConfigurationClass():
- processDeferredImportSelectors(): 处理须要延迟处理的ImportSelector . 这里的延迟加载最终仍是会走processImports()逻辑.
由于第二步最终仍是走第一步,因此只研究第一步。
doProcessConfigurationClass : 解析ConfigurationClass:(解析的过程涉及到不少递归. 经过一个ArrayDeque双端栈来存储当前的ConfigurationClass)
- processMemberClasses 递归处理内部类. 检查当前ConfigurationClas的内部类是不是一个ConfigurationClass. 若是是递归processConfigurationClass()-->doProcessConfigurationClass().
- 处理@PropertySource注解
- 处理 @ComponentScan注解: 这里也有一个递归操做. 检查扫描的定义集以获取任何进一步的配置类,并在须要时递归解析.这会用ComponentScanAnnotationParser解析器找到定义集中全部被@Component标注的类. 把其也当作一个ConfigurationClass. 而后递归解析ConfigurationClass
- processImports() 递归解析@Import注解引入的配置类. @Import导入的类会分红三种状况来处理.【具体看下面processImports()解析】
- 处理@ImportResource 注解. 把引入的资源值添加当前ConfigurationClass的importedResources属性上.
- 处理@Bean:查看当前ConfigurationClass是否有@Bean的方法. 有就添加到ConfigurationClass的beanMethods属性上.
- 若是父类superclass存在,而且不是
java
包中的类,而且还没有处理处理则返回它以便外层循环继续. 这也是为啥doProcessConfigurationClass会嵌套在一个do while的缘由.
processImports():@Import导入的类会分红三种状况来处理.
(1)导入的是一个实现了ImportSelector接口的类.
- 若是实现DeferredImportSelector则做为延迟处理对待.放到deferredImportSelectors 缓存中在processDeferredImportSelectors()分支中处理
- 若是实现ImportSelector,执行selectImports方法递归处理可能被@Import注解的ConfigurationClass
(2)导入的是一个实现了ImportBeanDefinitionRegistrar接口的类:
- 代表有须要手动注册Bean到容器中操做. 把实现类添加到当前ConfigurationClass的importBeanDefinitionRegistrars属性中.
(3)普通类,则把他当作一个ConfigurationClass处理走递归解析.
- 当作一个ConfigurationClass递归处理.
小结:通过一些系列递归,解析后.最终的结果:就是搜集到ConfigurationClass . ConfigurationClass 里携带这各类各样的Bean定义.
今后处咱们也能够看出一些东西若是向容器中注册组件
- 注解@Controller/@Service/@Repository/@Component
- @Bean 返回的Bean .
- @Import 快速导入一个组件到容器中 :普通类或者 ImportSelector接口实现类;或者ImportBeanDefinitionRegistrar实现类
- @ImportResource 导入一个xml文件。
ConfigurationClassBeanDefinitionReader.loadBeanDefinitions()分支: 目的把ConfigurationClass中配置的BeanDefinition解析出来.(理解为解析xml文件中的Bean定义)
有了ConfigurationClass,下面就是解析. 就比如有了xml文件,就能够解析xml中的Bean定义同样.这部分讲讲ConfigurationClass中的BeanDefinition如何被解析出来.
循环遍历全部的找到的ConfigurationClass
- configClass.isImported():当前ConfigurationClass是不是经过别人经过@Import引入的,是,当作一个BeanDefinition注入到仓库中。
- configClass.getBeanMethods(): 将@Bean注解标致的方法的返回值解析成一个BeanDefinition注入到仓库中。
- loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()):加载当前ConfigurationClass中@ImportResource引入的xml文件中的Bean定义。具体是使用XmlBeanDefinitionReader读取器读取XML中配置的Bean定义, 解析成BeanDefinition注入到仓库中。
- loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()):取出实现了ImportBeanDefinitionRegistrar接口的类,执行其registerBeanDefinitions方法。注册相应的BeanDefinition到仓库中。
小结:
将ConfigurationClass中的BeanDefinition解析出来放入到仓库中即完成了 BeanDefinition的搜集工做。
回看上面的若是向容器中注册组件
除去注解@Controller/@Service/@Repository/@Component标致的类被解析ConfigurationClass自己也是一种BeanDefinition外。
loadBeanDefinitions()解析的就是针对后三种方式的注册Bean方式:
- @Bean 标注
- @Import 引入的三种。
- @ImportResource 引入的xml文件。
总结:
总结来看:BeanDefinition的搜集入库阶段,其实就是找Bean定义的配置文件(ConfigurationClass), 解析文件中Bean定义(BeaDefinition), 而后入库到仓库中的过程。
欢迎你们关注个人公众号【源码行动】,最新我的理解及时奉送。