spring源码解析(五)-finishBeanFactoryInitialization

介绍:

前面三篇文章小编介绍了spring启动过程中的三个重要方法:obtainFreshBeanFactory、invokeBeanFactoryPostProcessors、invokeBeanFactoryPostProcessors。。。。那么还有一个更为重要的方法,也是sping源码的核心部分------普通bean的创建和初始化的过程。。。。。

 

概述:

该方法会实例化所有剩余的非懒加载单例 bean。除了一些内部的 bean、实现了 BeanFactoryPostProcessor 接口的 bean、实现了 BeanPostProcessor 接口的 bean,其他的非懒加载单例 bean 都会在这个方法中被实例化,并且 BeanPostProcessor 的触发也是在这个方法中。

 

 

前序:

在进入正文之前,我这里先简单介绍一个概念MergedBeanDefinition


在之后的内容你可能会频繁的见到 MergedBeanDefinition,先介绍一下这个bean定义。

MergedBeanDefinition:这个词其实不是一个官方词,但是很接近,该词主要是用来表示 “合并的 bean 定义”,因为每次都写 “合并的 bean 定义” 有点太绕口,因此我在之后的注释或解析中或统一使用 MergedBeanDefinition 来表示 “合并的 bean 定义”。

之所以称之为 “合并的”,是因为存在 “子定义” 和 “父定义” 的情况。对于一个 bean 定义来说,可能存在以下几种情况:

1、 该 BeanDefinition 存在 “父定义”:首先使用 “父定义” 的参数构建一个 RootBeanDefinition,然后再使用该 BeanDefinition 的参数来进行覆盖。
2 、该 BeanDefinition 不存在 “父定义”,并且该 BeanDefinition 的类型是 RootBeanDefinition:直接返回该 RootBeanDefinition 的一个克隆。
3、 该 BeanDefinition 不存在 “父定义”,但是该 BeanDefinition 的类型不是 RootBeanDefinition:使用该 BeanDefinition 的参数构建一个 RootBeanDefinition。
之所以区分出2和3,是因为通常 BeanDefinition 在之前加载到 BeanFactory 中的时候,通常是被封装成 GenericBeanDefinition ScannedGenericBeanDefinition,但是从这边之后 bean 的后续流程处理都是针对 RootBeanDefinition,因此在这边会统一将 BeanDefinition 转换成 RootBeanDefinition

在我们日常使用的过程中,通常会是上面的第3种情况。如果我们使用 XML 配置来注册 bean,则该 bean 定义会被封装成:GenericBeanDefinition;如果我们使用注解的方式来注册 bean,也就是 + @Compoment,则该 bean 定义会被封装成 ScannedGenericBeanDefinition。
 


正文:我们找到finishBeanFactoryInitialization方法,,点击进去:

spring源码解析(五)-finishBeanFactoryInitialization_第1张图片

finishBeanFactoryInitialization

spring源码解析(五)-finishBeanFactoryInitialization_第2张图片

实例化所有剩余(非懒加载)单例对象,见代码块1详解

代码块1:preInstantiateSingletons

spring源码解析(五)-finishBeanFactoryInitialization_第3张图片

spring源码解析(五)-finishBeanFactoryInitialization_第4张图片

spring源码解析(五)-finishBeanFactoryInitialization_第5张图片

3.获取 beanName 对应的 MergedBeanDefinition,见代码块2详解。

5.判断 beanName 对应的 bean 是否为 FactoryBean,见代码块6详解

5.3 和 6 通过 beanName 获取 bean 实例,是finishBeanFactoryInitialization 方法的核心,暂不做深入分析。。

7.遍历 beanNames,触发所有 SmartInitializingSingleton 的后初始化回调,这是 Spring 提供的一个扩展点,在所有非懒加载单例实例化结束后调用

代码块2:getMergedLocalBeanDefinition

spring源码解析(五)-finishBeanFactoryInitialization_第6张图片

3.2 根据 beanName 和 beanName 对应的 BeanDefinition,获取 MergedBeanDefinition,见代码块3详解

代码块3:getMergedBeanDefinition

spring源码解析(五)-finishBeanFactoryInitialization_第7张图片

 

spring源码解析(五)-finishBeanFactoryInitialization_第8张图片

 

spring源码解析(五)-finishBeanFactoryInitialization_第9张图片

 

5.1 获取父定义的 beanName,这边有一个 beanName 的转换操作,之后会经常用到,见代码块4详解。

5.3 获取父定义的 MergedBeanDefinition,见代码块5详解。

5.7 和 5.8 就是合并操作,也就是我们之前一直说的 MergedBeanDefinition 的由来。


8.将该 beanName 与 MergedBeanDefinition 放到 mergedBeanDefinitions 缓存,后续再走到代码块2时,就会直接返回缓存里的数据。

 

代码块4:transformedBeanName

spring源码解析(五)-finishBeanFactoryInitialization_第10张图片

spring源码解析(五)-finishBeanFactoryInitialization_第11张图片

 

spring源码解析(五)-finishBeanFactoryInitialization_第12张图片

如上:将 name 真正解析成真正的 beanName,主要是去掉 FactoryBean 里的 “&” 前缀,和解析别名。这边简单的介绍下 FactoryBean。

FactoryBean
一般情况下,Spring 通过反射机制利用 bean 的  class 属性指定实现类来实例化 bean。而 FactoryBean 是一种特殊的 bean,它是个工厂 bean,可以自己创建 bean 实例,如果一个类实现了 FactoryBean 接口,则该类可以自己定义创建实例对象的方法,只需要实现它的 getObject() 方法

如下代码:

spring源码解析(五)-finishBeanFactoryInitialization_第13张图片

 

 

代码块5:getMergedBeanDefinition

spring源码解析(五)-finishBeanFactoryInitialization_第14张图片

这边引入了一个 “父 BeanFactory” 的概念

父BeanFactory:

在 Spring 中可能存在多个 BeanFactory,多个 BeanFactory 可能存在 “父工厂” 与 “子工厂” 的关系。最常见的例子就是:Spring MVC 的 BeanFactory 和 Spring 的 BeanFactory,通常情况下,Spring 的 BeanFactory 是 “父工厂”,Spring MVC 的 BeanFactory 是 “子工厂”,在 Spring 中,子工厂可以使用父工厂的 BeanDefinition,因而,如果在当前 BeanFactory 中找不到,而又存在父工厂,则会去父工厂中查找。

代码块6:isFactoryBean


spring源码解析(五)-finishBeanFactoryInitialization_第15张图片

 

2.尝试从缓存获取 bean 实例对象,见代码块7详解

6.通过 MergedBeanDefinition 来检查 beanName 对应的 bean 是否为 FactoryBean。首先通过 getMergedLocalBeanDefinition 方法获取 beanName 的 MergedBeanDefinition,该方法在代码块2已经解析过;接着调用 isFactoryBean 来检查 beanName 对应的 bean 是否为 FactoryBean,见代码块8详解。


代码块7:getSingleton

spring源码解析(五)-finishBeanFactoryInitialization_第16张图片

这段代码很重要,在正常情况下,该代码很普通,只是正常的检查下我们要拿的 bean 实例是否存在于缓存中,如果有就返回缓存中的 bean 实例,否则就返回 null。

这段代码之所以重要,是因为该段代码是 Spring 解决循环引用的核心代码。

 

解决循环引用逻辑:使用构造函数创建一个 “不完整” 的 bean 实例(之所以说不完整,是因为此时该 bean 实例还未初始化),并且提前曝光该 bean 实例的 ObjectFactory(提前曝光就是将 ObjectFactory 放到 singletonFactories 缓存),通过 ObjectFactory 我们可以拿到该 bean 实例的引用,如果出现循环引用,我们可以通过缓存中的 ObjectFactory 来拿到 bean 实例,从而避免出现循环引用导致的死循环。这边通过缓存中的 ObjectFactory 拿到的 bean 实例虽然拿到的是 “不完整” 的 bean 实例,但是由于是单例,所以后续初始化完成后,该 bean 实例的引用地址并不会变,所以最终我们看到的还是完整 bean 实例。

这段解决逻辑涉及到了后面的一些内容,所以可能会看的不是很理解,建议吧整个bean创建看完再回头看。。。。。

这个代码块中引进了4个重要缓存:

1、singletonObjects 缓存:beanName -> 单例 bean 对象。
2、earlySingletonObjects 缓存:beanName -> 单例 bean 对象,该缓存存放的是早期单例 bean 对象,可以理解成还未进行属性填充、初始化。
3、singletonFactories 缓存:beanName -> ObjectFactory。
4、singletonsCurrentlyInCreation 缓存:当前正在创建单例 bean 对象的 beanName 集合。
singletonObjectsearlySingletonObjectssingletonFactories 在这边构成了一个类似于 “三级缓存” 的概念。

代码块8:isFactoryBean


spring源码解析(五)-finishBeanFactoryInitialization_第17张图片

1.拿到 beanName 对应的 bean 实例的类型,见代码块9详解

代码块9:predictBeanType

spring源码解析(五)-finishBeanFactoryInitialization_第18张图片

这边走的是 AbstractAutowireCapableBeanFactory 里的方法,而不是 AbstractBeanFactory 里的方法。通过前面的介绍,我们知道创建的 BeanFactory 为 DefaultListableBeanFactory,而 DefaultListableBeanFactory 继承了 AbstractAutowireCapableBeanFactory,因此这边会走 AbstractAutowireCapableBeanFactory 的重写方法。
 

 

划重点:

本文执行了创建 bean 实例前的一些准备操作。主要是引入了 FactoryBean 这一特殊的 bean,获取 BeanDefinition 的 MergedBeanDefinition,最后将 BeanDefinition 统一转换成 RootBeanDefinition

另外,本文还引入了几个重要的缓存,如下:

mergedBeanDefinitions 缓存:beanName -> 合并的 bean 定义。
beanDefinitionMap 缓存:beanName -> BeanDefinition。
singletonObjects 缓存:beanName -> 单例 bean 对象。
earlySingletonObjects 缓存:beanName -> 单例 bean 对象,该缓存存放的是早期单例 bean 对象,可以理解成还未进行属性填充、初始化。
singletonFactories 缓存:beanName -> ObjectFactory。
singletonsCurrentlyInCreation 缓存:当前正在创建单例 bean 对象的 beanName 集合。
Spring 中大量使用了本地缓存,基本上通过名字和注释就能理解缓存的作用了。

后面的文章中,我们重点介绍核心方法-----doGetBean(获取bean方法)

你可能感兴趣的:(spring,spring)