BeanDefinition & createBean
分析Bean在spring中解析后的定义BeanDefinition,以及createBean的过程
测试的代码如下:
main
1 | public class Hello { |
pom.xml
1 |
|
beans.xml
1 |
|
BeanDefinition
在上一篇分析基本容器的时候,解析配置文件,扫描Bean,找到Bean的定义 – BeanDefinition是在DefaultBeanDefinitionDocumentReader中完成的。
扫描我们的bean的配置文件,拿到配置文件的解析结果Element对象,并根据不同的标签类型使用不同的方法解析,基本代码如下:
1 |
|
剩下的任务就是解析每一个扫描xml文件中得出的Element标签,并将Element对象转换为bean的定义对象BeanDefinition。而这些任务在Spring的架构中都是委托给BeanDefinitionParserDelegate实现的,该类是专门负责将Elementxml标签对象,转换为相应的BeanDefinition对象。
下面我们先看下BeanDefinitionParserDelegate的初始化过程:
1 | // DefaultBeanDefinitionDocumentReader 中 |
然后,我们再来认识下ReaderContext。一般使用的是他的子类XmlReaderContext
1 | /** |
在Spring中,像使用
ReaderContext这种环境类特别多,这种设计模式应该细细品味,好好体会,有时间了还应该专门写一篇日志分析记录一下。
好,到这里,基础工作做好了之后,下面开始真正的解析。
首先看看解析bean标签的过程。processBeanDefinition
1 | protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { |
第一步:解析标签,完成Element 到 BeanDefinition 的转换。
1 | /** |
第二步,就是根据扫描一下自定义属性什么的,看源码,就是根据命名空间这些,去找相应标签的相应属性有没有被定义等等。
第三步,注册到Registry,也就是我们的BeanFactory
1 | // BeanDefinitionReaderUtils |
到这里为止,根root下的所有bean element都以BeanDefinition的形式保存在了BeanFactory中。
其他类型的基本标签和这个过程都是类似的,比bean标签简单,而且最后都要回归到bean标签。
createBean
现在,所有的bean都以BeanDefinition的格式保存在BeanFactory中。当调用类似getBean方法的时候就会实例化该bean。
这是我们的入口:
1 | Student myBean = beanFactory.getBean("myBean", Student.class); |
到最后都是执行的AbstractBeanFactory.doCetBean
1 | protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, |
整个getBean的流程都包含在上面的函数中,总体应该分为两大类来讨论,一个是singleton,一个是普通类Prototype
Prototype 类型的实例化
首先,分析普通类型的实例化。 每次getBean 都需要 调用createBean,整个逻辑也比较简单。
在之前,先了解一下整个过程涉及到的几个变量。他们都在AbstractBeanFactory
1 | public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory { |
mergedBeanDefinitions每个bean在创建之前都需要将普通的BeanDefinition转换为RootBeanDefinition也就是该成员变量中存储的对象。 而且,他也作为创建对象过程中的同步锁,alreadyCreated每个第一次创建的对象的 beanName都会被保存到该成员变量中。也是用来标志创建过程是否开始,某个bean是否开始创建prototypesCurrentlyInCreation主要是针对Prototype(普通)类型的bean。因为可能被同时多个线程创建,所以保存在ThreadLocal`中.
下面我们看 整个bean的创建过程:
第一步,检测是否仅仅是来检查类型的,如果不是,那就是来创建对象的,就将该对象标记被在创建中。markAsCreated()代码上面已经给出了。
第二步,getMergedLocalBeanDefinition。整个merge的过程就是将 父BeanDefinition合并到子BeanDefinition中。整个过程的细节以及几个BeanDefinition关系可以查看bean的parent属性详解和获取RootBeanDefinition。该步骤会设置默认scope为singleton
1 | protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException { |
第三步,获取依赖。就是检测BeanDefinition中dependOn属性,get所有dependOn的bean。
第四步,创建实例。
第五步,调用getObjectForBeanInstance,获取真正的实例对象。
1 | protected Object getObjectForBeanInstance( |
Singleton 类型的实例化
用来操作Singleton相关实例的类是DefaultSingletonBeanRegistry,首先,先来好好了解下该类。
1 | public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { |
第一步,查看之前解析过没有。不管是之前放到early,singletonFactories中 都可以获取到。剩下的和Prototype基本差不多。
第二步,从parent BeanFactory获取。
第三步,标记创建中
第四步,mergeBeanDefinition
第五步,createBeanInstance
除了createBean之外,还有一些singletonBean的特殊操作。
1 | public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { |
第六步,调用getObjectForBeanInstance,获取真正的实例对象。
doCreateBean
整个创建bean的过程 大致如下:
- 给
InstantiationAwareBeanPostProcessor接口最后的机会,在实例化之前修改bean。 - 进入 doCreateBean
- 创建对象实例
- 给
MergedBeanDefinitionPostProcessor接口修改RootBeanDefinition的机会 - 应用 BeanDefinition 中的 property
- 如果存在,回调接口 InstantiationAwareBeanPostProcessor 的方法 postProcessAfterInstantiation
- 将PropertyValue中的 beanName beanClass 替换为 对应的 bean 实例
- 如果存在,调用 接口 InstantiationAwareBeanPostProcessor 的方法 postProcessPropertyValues 对PropertyValues 应用修改
- 最后将 PropertyValues 赋值给 bean 实例对象
- 调用初始化方法
- 如果该bean 实现了 aware 接口,则调用相应aware 接口的set方法
- BeanPostProcessor.postProcessBeforeInitialization
- 如果实现了接口InitializingBean,则回调 afterPropertySet 方法
- 调用 init 方法
- BeanPostProcessor.postProcessAfterInitialization
doCreateBean
1 | protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) |
populateBean
1 | protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { |
initializeBean
1 | protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { |
其他的 doCreateBean 很多代码都没有分析,是这些代码主要在做一些 singleton 循环引用的处理。