概述
Bean 的加载涉及到 获取 Bean 定义,实例化、属性填充、初始化过程。
在初始化阶段 ,Spring 对 Aware、BeanPostProcessor 等扩展点进行了实现,对 Bean 进行增强。
在初始化阶段,有将 Bean 放到三级缓存,然后到二级缓存,最后初始化完成放到一级缓存的过程,具体可以看看上篇文章。
Spring Bean 加载过程生命周期源码分析
注意:
- Spring 只解决了单例 Bean 循环依赖的情况
-
样例代码
样例代码只包含 3 个类,启动类 SpringBeanCircleApplication ,CircularServiceA 依赖 CircularServiceB,CircularServiceB 依赖 CircularServiceA 。 ```java @SpringBootApplication public class SpringBeanCircleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBeanCircleApplication.class, args);
} }
@Service public class CircularServiceA {
@Autowiredprivate CircularServiceB circularServiceB;
}
@Service public class CircularServiceB {
@Autowiredprivate CircularServiceA circularServiceA;
}
<a name="kw9qy"></a># 源码分析循环依赖的 Bean 加载流程:1. A 的**加载流程**包括**实例化、属性填充、初始化**三个阶段。A 实例化完成之后,会将 Bean 标记为**创建中**(还未属性填充、初始化)、并且实例的 objectFactory 加入到三级缓存。其中在 A **属性填充**阶段,发现 B 还未加载,进而去执行 B 的加载流程1. B 的加载流程和 A 一样,B 实例化完成后,会将 B 标记为创建中、加入到三级缓存。此时三级缓存中有 A、B 的 ObjectFactory。1. 在 B **属性填充**阶段,又发现 A ,进而**又去加载 A** 。加载 A 发现其正在**创建中**,并且三级缓存中有 A,那么将 A 放到二级缓存,并返回 A 的引用。1. 至此 B 属性填充完成,再执行 B 初始化,初始化完成后将 B 从三级移动到二级再移动到一级缓存中。1. 再执行 A 属性填充后的初始化流程,并放到一级缓存。最终,一级缓存里面包含 A 和 B 初始化完成的实例沿用网上一张图片:<br /><a name="bKUGI"></a>## 1. getBean(A)A 的加载流程<a name="vIF5O"></a>### 1.1 AbstractBeanFactory- 从 getBean 开始,首先从缓存中获取(**这个步骤很重要**)- 若缓存中没有,再获取 A 的定义,其次调用 getSingleton 去获取 A 的实例,createBean 方法用于创建 A 的 objectFactory。- 若缓存中有,直接返回实例```javapublic abstract class AbstractBeanFactory {public Object getBean(String name) throws BeansException {return this.doGetBean(name, (Class)null, (Object[])null, false);}protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {Object sharedInstance = this.getSingleton(beanName); // 从缓存中获取 A,第一次显然获取不到try {RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName); // 获取 Bean 定义if (mbd.isSingleton()) {// 获取 A 的实例sharedInstance = this.getSingleton(beanName, () -> {try {return this.createBean(beanName, mbd, args); // 执行 singletonFactory.getObject 会被调用} catch (BeansException var5) {this.destroySingleton(beanName);throw var5;}});beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}}}}
1.2 DefaultSingletonBeanRegistry
- getSingleton(String beanName, ObjectFactory<?> singletonFactory) 执行到 singletonFactory.getObject 这一行时,会调用函数调用的地方 Lamda 表达式的 AbstractAutowireCapableBeanFactory.createBean 方法
getSingleton 方法结束部分,表示 Bean 已经初始化完成,此时移除 Bean 创建中标记,并加入到一级缓存中
public class DefaultSingletonBeanRegistry {public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {synchronized(this.singletonObjects) {Object singletonObject = this.singletonObjects.get(beanName); // 再次从缓存中获取 A,显然获取不到if (singletonObject == null) {this.beforeSingletonCreation(beanName); // 标记创建中,加入到 singletonsCurrentlyInCreationtry {singletonObject = singletonFactory.getObject(); // 执行 lamda 表达式,AbstractAutowireCapableBeanFactory.createBean 返回 实例newSingleton = true;} finally {// A 加载结束,移除正在创建标记 singletonsCurrentlyInCreationthis.afterSingletonCreation(beanName);}if (newSingleton) {// 添加到一级缓存,删除二级缓存与一级缓存this.addSingleton(beanName, singletonObject);}}}}}
1.3 AbstractAutowireCapableBeanFactory
执行具体 Lamda 表达式的内容,注意属性填充前,将对象加入的三级缓存的部分,后面会说到三级缓存的作用 ```java public abstract class AbstractAutowireCapableBeanFactory { protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
beanInstance = this.doCreateBean(beanName, mbdToUse, args);
}
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
if (instanceWrapper == null) {instanceWrapper = this.createBeanInstance(beanName, mbd, args); // A 实例化}// 是否单例 && 运行循环依赖 && 创建中boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);if (earlySingletonExposure) {// 将对象放到三级缓存this.addSingletonFactory(beanName, () -> {return this.getEarlyBeanReference(beanName, mbd, bean);});}try {this.populateBean(beanName, mbd, instanceWrapper); // 属性填充(此时发现 A )exposedObject = this.initializeBean(beanName, exposedObject, mbd); // 初始化}if (earlySingletonExposure) {// 只从一级缓存和二级缓存中取Object earlySingletonReference = this.getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}}}
} }
// 属性填充 protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { if (resolvedAutowireMode == 1 || resolvedAutowireMode == 2) { MutablePropertyValues newPvs = new MutablePropertyValues((PropertyValues)pvs); if (resolvedAutowireMode == 1) { this.autowireByName(beanName, mbd, bw, newPvs); }
if (resolvedAutowireMode == 2) {this.autowireByType(beanName, mbd, bw, newPvs);}pvs = newPvs;}
}
protected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) { for(int var8 = 0; var8 < var7; ++var8) { String propertyName = var6[var8]; if (this.containsBean(propertyName)) { // 如果含有 Bean,那么执行 Bean 加载逻辑 Object bean = this.getBean(propertyName); // A 发现 B,那么执行 B 的加载流程 } }
}
**可以发现,在 A 的 populateBean 阶段,会去调用 getBean(B) 的逻辑**<a name="D7agh"></a>## 2. getBean(B)B 的加载流程,其加载流程和 A 一样(1.1,1.2,1.3 部分)<br />**重点来了,在 B 的 populateBean 阶段,又发现了 A,此时再去执行 getBean(A)**<a name="umAd1"></a>## 3. getBean(A)A 再次被加载<br />AbstractBeanFactory.getBean 方法开头,发现此时**三级缓存**中有 A 的 ObjectFactory,并且标记为创建中,那么把 A 的 ObjectFactory **从三级缓存**(singletonFactories)**放到二级缓存**(earlySingletonObjects)中,并返回 A 的提前曝光实例(还未初始化完成)```javapublic abstract class AbstractBeanFactory {protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {Object sharedInstance = this.getSingleton(beanName);if (sharedInstance != null && args == null) {beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);}}public class DefaultSingletonBeanRegistry{@Nullablepublic Object getSingleton(String beanName) {return this.getSingleton(beanName, true);}// 从缓存获取逻辑@Nullableprotected Object getSingleton(String beanName, boolean allowEarlyReference) {Object singletonObject = this.singletonObjects.get(beanName); // 从一级缓存获取if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) { // 没有获取到并且正在创建中singletonObject = this.earlySingletonObjects.get(beanName); // 从二级缓存获取if (singletonObject == null && allowEarlyReference) { // 二级缓存也没有获取到,并且允许提前返回引用synchronized(this.singletonObjects) { // 加锁singletonObject = this.singletonObjects.get(beanName); // 再次从一级缓存获取if (singletonObject == null) { // 一级没有singletonObject = this.earlySingletonObjects.get(beanName); // 二级中获取if (singletonObject == null) { // 二级也没有ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName); // 从三级获取if (singletonFactory != null) {singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject); // 从三级中获取到了,删除三级缓存,加入到二级缓存中this.singletonFactories.remove(beanName);}}}}}}return singletonObject;}}
4. B 初始化完成
上一步 B 属性填充完成之后,执行 AbstractAutowireCapableBeanFactory 中后续的初始化流程、并在 DefaultSingletonBeanRegistry.getSingleton 方法最后,移除 Bean 创建中标记,将缓存从三级移到一级。
5. A 初始化完成
为什么需要三级缓存
根据上面流程可知,A、B 的加载,首先都会放到三级缓存中,当再次调用 getBean(A) 方法时,从三级缓存中通过 ObjectFactory.getObject 获取 A 的实例。
若 A 被 AOP 代理,那么执行匿名表达式的exposedObject = bp.getEarlyBeanReference(exposedObject, beanName)操作,返回的是 A 的代理对象
可以用反证法证明三级缓存的必要性:
- 若只有两级缓存,创建 A 实例时,不知道是否有循环依赖,先将 A 放到二级缓存;创建 B 实例时,也放入二级缓存。
- B 属性填充阶段发现了 A,进从二级缓存中找到了 A,若 A 被 AOP 代理,此时从二级缓存中获取的 A 是原始对象并不是代理对象,不符合要求。
- 若一开始将 A 的代理对象放入二级缓存,这样违背了 Spring AOP 与 Bean 的生命周期的设计,因为在没有循环依赖的常规情况下,AOP 的实现都是 Bean 初始化完成之后才进行。
所以若出现了循环依赖,三级缓存就很有必要,把实例对象的 ObjectFactory 放到三级缓存中,通过 singletonFactory.getObject() 方法判断是否需要返回 A 的代理类,对 A 提前做增强。
public abstract class AbstractAutowireCapableBeanFactory {protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {// 是否单例 && 运行循环依赖 && 创建中boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);if (earlySingletonExposure) {// 将对象放到三级缓存this.addSingletonFactory(beanName, () -> {return this.getEarlyBeanReference(beanName, mbd, bean);});}}protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;SmartInstantiationAwareBeanPostProcessor bp;// 有代理if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {// for 循环参数结尾,返回实例的提前曝光对象for(Iterator var5 = this.getBeanPostProcessorCache().smartInstantiationAware.iterator(); var5.hasNext(); exposedObject = bp.getEarlyBeanReference(exposedObject, beanName)) {bp = (SmartInstantiationAwareBeanPostProcessor)var5.next();}}// 返回可能被代理的对象return exposedObject;}}
循环依赖情况
| 依赖情况 | 依赖注入方式 | 循环依赖是否被解决 | | —- | —- | —- | | AB相互依赖(循环依赖) | 均采用 setter 方法注入 | 是 | | AB相互依赖(循环依赖) | A中注入B的方式为setter方法 | 是 | | AB相互依赖(循环依赖) | B中注入A的方式为 setter 方法,A中注入B的方式为构造器 | 否 | | AB相互依赖(循环依赖) | B中注入A的方式为setter方法,A中注入B的方式为构造器 | 是(可以使用 @Lazy 解决) |
- Spring 创建 Bean 是按照自然排序,若主 Bean 是 setter 方式,那么依赖 Bean 是 setter 注入或者构造器注入,都可以解决循环依赖问题
- 均使用构造器注入,可以使用 @Lazy 解决,其基本思路是:对于强依赖的对象,一开始并不注入对象本身,而是注入其代理对象
```java
@Service
public class CircularServiceA {
private CircularServiceB circularServiceB;
public CircularServiceA(@Lazy CircularServiceB circularServiceB){
} }this.circularServiceB = circularServiceB;
@Service public class CircularServiceB { private CircularServiceA circularServiceA; public CircularServiceB(CircularServiceA circularServiceA){ this.circularServiceA = circularServiceA; } } ```
