Spring源码分析-getBean
前言
接着 Spring IoC:finishBeanFactoryInitialization详解,我们正式开始学习获取 bean 实例方法,该方法是 Spring 最核心的方法。
单击 preInstantiateSingletons 方法里的 getBean(beanName) 代码,进入该方法。
流程图
getBean
实例化Bean的核心方法
1 | /** |
doGetBean
1 | /** |
getObjectForBeanInstance
获取给定bean实例的对象,或者实例本身或FactoryBean创建的对象
1 | /** |
isFactoryDereference
来到BeanFactoryUtils类
是否是FactoryBean,检查name不为空并且name是以 “&” 符号开头的
1 | /** |
getObjectFromFactoryBean
从FactoryBean中获取对象
1 | /** |
doGetObjectFromFactoryBean
调用getObject获取bean实例
1 | /** |
很简单的方法,就是直接调用 FactoryBean 的 getObject 方法来获取到对象实例。
细心的同学可以发现,该方法是以 do 开头, do 开头的方法是最终进行实际操作的方法,例如本方法就是 FactoryBean 最终实际进行创建 bean 对象实例的方法。
postProcessObjectFromFactoryBean
是一个扩展点,使用BeanPostProcessor对bean实例化之前进行一些调用
1 |
|
这边走的是 AbstractAutowireCapableBeanFactory 里的方法。通过前面的介绍,我们知道创建的 BeanFactory 为 DefaultListableBeanFactory,而 DefaultListableBeanFactory 继承了 AbstractAutowireCapableBeanFactory,因此这边会走 AbstractAutowireCapableBeanFactory 的重写方法。
markBeanAsCreated
1 | /** |
这边会将 beanName 对应的 MergedBeanDefinition 移除,然后在之后的代码重新获取,主要是为了使用最新的 MergedBeanDefinition 来进行创建操作。
isDependent
循环依赖检查
1 | /** |
这边引入了一个缓存 dependentBeanMap:beanName -> 所有依赖 beanName 对应的 bean 的 beanName 集合。内容比较简单,就是检查依赖 beanName 的集合中是否包含 dependentBeanName,隔层依赖也算。例如:A 依赖了 B,B 依赖了 C,则 A 也算依赖了 C。
registerDependentBean
1 | /** |
这边又引入了一个跟 dependentBeanMap 类似的缓存,dependenciesForBeanMap:beanName -> beanName 对应的 bean 依赖的所有 bean 的 beanName 集合。
这两个缓存很容易搞混,举个简单例子:例如 B 依赖了 A,则 dependentBeanMap 缓存中应该存放一对映射:其中 key 为 A,value 为含有 B 的 Set;而 dependenciesForBeanMap 缓存中也应该存放一对映射:其中 key 为:B,value 为含有 A 的 Set。
getSingleton
针对不同的scope进行bean的创建
入口代码
1 | //获取单例的实例,单例的核心入口 |
代码解析
1 | /** |
beforeSingletonCreation&afterSingletonCreation
添加正在实例化的bean,解决循环依赖
1 | /** |
inCreationCheckExclusions 是要在创建检查排除掉的 beanName 集合,正常为空,可以不管。这边主要是引入了 singletonsCurrentlyInCreation 缓存:当前正在创建的 bean 的 beanName 集合。在 beforeSingletonCreation 方法中,通过添加 beanName 到该缓存,可以预防出现构造器循环依赖的情况。
为什么无法解决构造器循环依赖?
我们之前在 Spring IoC:finishBeanFactoryInitialization详解 中的代码块getSingleton 提过,getSingleton 方法是解决循环引用的核心代码。解决逻辑的第一句话:“我们先用构造函数创建一个 “不完整” 的 bean 实例”,从这句话可以看出,构造器循环依赖是无法解决的,因为当构造器出现循环依赖,我们连 “不完整” 的 bean 实例都构建不出来。Spring 能解决的循环依赖有:通过 setter 注入的循环依赖、通过属性注入的循环依赖。
addSingleton
将实例化完成的单例对象添加到单例对象缓存
1 | /** |
beforePrototypeCreation&afterPrototypeCreation
使用prototypesCurrentlyInCreation 来阻断prototype的循环依赖
1 | /** |
该方法和代码块beforeSingletonCreation&afterSingletonCreation的两个方法类似。主要是在进行 bean 实例的创建前,将 beanName 添加到 prototypesCurrentlyInCreation 缓存;bean 实例创建后,将 beanName 从 prototypesCurrentlyInCreation 缓存中移除。这边 prototypesCurrentlyInCreation 存放的类型为 Object,在只有一个 beanName 的时候,直接存该 beanName,也就是 String 类型;当有多个 beanName 时,转成 Set 来存放。
总结
本文介绍了获取 bean 实例的大部分内容,包括先从缓存中检查、 FactoryBean 的 bean 创建、实例化自己的依赖(depend-on 属性)、创建 bean 实例的前后一些标记等,在下篇文章中,将解析创建 bean 的内容。