什么是循环依赖?
在我们的开发中,会不可避免的遇到Bean之间循环依赖的,所谓循环依赖,就是两个或者两个以上的Bean互相持有对方,这样在程序运行调用中,会出现这种循环依赖的现象,其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。
举个简单的例子,两个Bean的循环依赖:
@Service
public class Demo1 {
@Autowired
private Demo2 demo2;
public void test1() {
}
}
@Service
public class Demo2{
@Autowired
private Demo1 demo1;
public void test2() {
}
}
这个就是循环依赖。
依赖分为三种:
- 自己依赖自己
- 两个对象相互依赖
- 多个对象相互依赖
什么是三级缓存?
singletonObjec
:用于存放完全初始化好的 bean,从该缓存中取出的 bean 可以直接使用
earlySingletonObjects
:提前曝光的单例对象的cache,存放原始的 bean 对象(尚未填充属性),用于解决循环依赖
singletonFactories
:单例对象工厂的cache,存放 bean 工厂对象,用于解决循环依赖
看下面代码前建议先了解Bean的创建流程:https://blog.csdn.net/wang121213145/article/details/124748726
详细代码:
在spring中的DefaultSingletonBeanRegistry
的getSingleton()
方法
执行流程
- 第一层,先去获取 A 的 Bean,发现没有就准备去创建一个,然后将 A 的代理工厂放入“三级缓存”(这个 A 其实是一个半成品,还没有对里面的属性进行注入),但是 A 依赖 B 的创建,就必须先去创建 B;
- 第二层,准备创建 B,发现 B 又依赖 A,需要先去创建 A;
- 第三层,去创建 A,因为第一层已经创建了 A 的代理工厂,直接从“三级缓存”中拿到 A 的代理工厂,获取 A 的代理对象,放入“二级缓存”,并清除“三级缓存”;
- 回到第二层,现在有了 A 的代理对象,对 A 的依赖完美解决(这里的 A 仍然是个半成品),B 初始化成功,并将B放入一级缓存
- 回到第一层,现在 B 初始化成功,完成 A 对象的属性注入,然后再填充 A 的其它属性,以及 A 的其它步骤(包括 AOP),完成对 A 完整的初始化功能(这里的 A 才是完整的 Bean),将 A 放入“一级缓存”。
如果没有采用三级缓存的话,会出现循环依赖,所以加入的第三级缓存,便于从对象工厂拿到创建的对象。