Spring bean循环依赖例子代码
Bean组件A : 依赖于Bean组件B
@Component
public class BeanA {
BeanB b;
@Autowired
public void setB(BeanB b) {
this.b = b;
}
public String describeB() {
return " ==引用==> BeanB 实例 :" + b;
}
}
Bean组件B : 依赖于Bean组件A
@Component
public class BeanB {
BeanA a;
@Autowired
public void setA(BeanA a) {
this.a = a;
}
public String describeA() {
return " ==引用==> BeanA 实例 :" + a ;
}
}
上面的循环依赖可以通过下图表示 :
上面的例子表达的是两个bean之间直接循环依赖,另外还会有两个bean之间间接循环依赖的情况,Spring对这两种循环依赖的处理并无不同,所以这里不再单独对间接循环依赖举例。
Spring 对bean循环依赖的解决
接下来我们结合Spring对单例bean统一的获取过程和有关的数据结构分析Spring 对单例bean循环依赖的解决。
Spring对单例bean统一的获取过程
Spring对单例bean的统一的获取过程为 :
// 类 AbstractBeanFactory
#getBean
=> #doGetBean
而方法#doGetBean主要流程如下 :
-
getSingleton(beanName,true)- 如果
singletonObjects包含beanName对应单例bean实例则返回之; - 如果
earlySingletonObjects包含beanName对应单例bean实例则返回之; - 如果
singletonFactories包含beanName对应单例bean实例工厂则:- 从对应单例
bean实例工厂获取单例bean实例; - 将所获取的单例
bean实例放到earlySingletonObjects; - 从
singletonFactories删除对应的单例bean实例工厂;
- 从对应单例
如果该步骤能获取到单例实例,则直接返回不再继续;
- 如果
-
getSingleton(String beanName, () -> {createBean(...)})- 标记单例实例处于创建过程中
createBean- 应用
InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation doCreateBeancreateBeanInstance创建对象- 应用
MergedBeanDefinitionPostProcessors addSingletonFactory(beanName, () -> getEarlyBeanReference(...))populateBean填充属性,依赖注入这里会递归触发所依赖的
bean的创建initializeBean初始化
- 应用
- 标记单例实例创建结束
- 将新建单例实例正式登记到单例注册表
- 将所创建的单例
bean实例放到singletonObjects; - 从
earlySingletonObjects删除对应的单例bean实例工厂; - 从
singletonFactories删除对应的单例bean实例工厂;
- 将所创建的单例
Spring辅助单例bean获取的数据结构
Spring使用了以下数据结构来保存处于不同创建阶段的单例bean实例 :
Map<String, Object> singletonObjects缓存已经创建完成的单例bean对象- 实例已经创建,并且已经完成属性设置,依赖注入和初始化
Map<String, Object> earlySingletonObjects缓存尽早暴露的单例bean对象- 实例已经创建,还没有完成属性设置,依赖注入和初始化
Map<String, ObjectFactory<?>> singletonFactories缓存单例bean名称和对应的ObjectFactory对象Set<String> singletonsCurrentlyInCreation当前正在创建过程中的单例bean的名称- 正在创建过程中的
bean实例
- 正在创建过程中的
分析组件BeanA/BeanB循环依赖的解决
为了方便描述,这里我们将BeanA单例实例的获取过程标记为#doGetBeanA,将BeanB单例实例的获取过程标记为#doGetBeanB。然后我们从#doGetBeanA的执行开始,结合以上辅助数据结构分析Spring对组件BeanA/BeanB循环依赖的解决。
#doGetBeanA开始之前
| 数据结构 | 对组件BeanA/BeanB的信息记录 |
|---|---|
singletonObjects | [] |
earlySingletonObjects | [] |
singletonFactories | [] |
#doGetBeanA执行步骤2.2.3结束时
| 数据结构 | 对组件BeanA/BeanB的信息记录 |
|---|---|
singletonObjects | [] |
earlySingletonObjects | [] |
singletonFactories | [beanA的ObjectFactory] |
#doGetBeanA执行到步骤2.2.4触发所依赖组件BeanB的获取
这一步骤会触发所依赖组件BeanB的获取,也就是我们上面我们所定义的过程#doGetBeanB的执行,#doGetBeanB开始之前以下数据结构状态保持跟上面相同 :
| 数据结构 | 对组件BeanA/BeanB的信息记录 |
|---|---|
singletonObjects | [] |
earlySingletonObjects | [] |
singletonFactories | [beanA的ObjectFactory] |
#doGetBeanB执行步骤2.2.3结束时
| 数据结构 | 对组件BeanA/BeanB的信息记录 |
|---|---|
singletonObjects | [] |
earlySingletonObjects | [] |
singletonFactories | [beanA的ObjectFactory,beanB的ObjectFactory] |
#doGetBeanB执行步骤2.2.4触发所依赖组件BeanA的获取
这一步骤会触发所依赖组件BeanA的获取,也就是我们上面我们所定义的过程#doGetBeanA的第二次执行,#doGetBeanA再次开始之前各数据结构保持跟上面一样 :
| 数据结构 | 对组件BeanA/BeanB的信息记录 |
|---|---|
singletonObjects | [] |
earlySingletonObjects | [] |
singletonFactories | [beanA的ObjectFactory,beanB的ObjectFactory] |
#doGetBeanA二次执行步骤1.3结束时
因为#doGetBeanA第一次执行已经在步骤2.2.3添加了组件BeanA的singletonFactory到singletonFactories,所以#doGetBeanA二次执行时会检测到该信息从而使用它直接创建组件BeanA的及早暴露实例并返回。
这里之所以将这里创建的组件
BeanA实例称作及早暴露实例,是因为整个#doGetBeanA过程尚未执行完成就需要将其实例暴露给使用者。
此时各个数据结构的内容如下 :
| 数据结构 | 对组件BeanA/BeanB的信息记录 |
|---|---|
singletonObjects | [] |
earlySingletonObjects | [beanA] |
singletonFactories | [beanB的ObjectFactory] |
一旦获取到组件BeanA单例实例,#doGetBeanB将可以继续执行直到#doGetBeanB执行到2.4步骤结束。
#doGetBeanB执行到步骤2.4结束时
各个数据结构的内容如下 :
| 数据结构 | 对组件BeanA/BeanB的信息记录 |
|---|---|
singletonObjects | [beanB] |
earlySingletonObjects | [beanA] |
singletonFactories | [] |
#doGetBeanB执行到步骤2.4结束时,也就意味着组件BeanB的创建结束了,#doGetBeanA的首次执行可以继续进行了,因为它现在拿到了所需要的依赖BeanB的单例实例。接下来,它会一直执行直到它的步骤2.4结束时。
#doGetBeanA执行到步骤2.4结束时
各个数据结构的内容如下 :
| 数据结构 | 对组件BeanA/BeanB的信息记录 |
|---|---|
singletonObjects | [beanA,beanB] |
earlySingletonObjects | [] |
singletonFactories | [] |
到此为止,存在循环依赖的组件BeanA/BeanB的单例实例获取就已经圆满完成了,相应的循环依赖属性也得到了正确的处理。
本文深入探讨Spring框架如何解决Bean之间的循环依赖问题,通过分析BeanA和BeanB的依赖关系,详细解释了Spring如何利用singletonObjects、earlySingletonObjects和singletonFactories等数据结构,确保即使在循环依赖的情况下也能正确创建和初始化Bean。
737





