在学习拉勾教育 Java 高薪训练营后,结合课程和老师的视频,自己跟踪源码后做的笔记。
以下面代码为例,A 依赖 B,B 依赖 A。
@Component public class A { private B b; public void setB(B b) { this.b = b; } } @Component public class B { private A a; public void setA(A a) { this.a = a; } }
循环依赖的原理类似死锁,解决方法同死锁一样,需要打破一方依赖,Spring 使用三级缓存来解决。
/** Cache of singleton objects: bean name to bean instance. */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); /** Cache of singleton factories: bean name to ObjectFactory. */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); /** Cache of early singleton objects: bean name to bean instance. */ private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
二级缓存和三级缓存的区别在于,二级缓存的 Bean 会增加一些扩展功能。比如二级缓存的 Bean 引用为动态代理, 先从三级缓存中获取 Bean,然后为其创建代理对象,之后放到二级缓存中,这也是为什么需要二级缓存的原因。
以 B 对象,A 属性为例,使用三级缓存 B 对象获取到的是半成品 A 对象(属性)的原始引用。如果在最后创建完成,放入一级缓存中的完成品 A 是代理引用,这与期望要求的不同,所以会多一个二级缓存,用于存放三级缓存的 Bean 的代理引用。
还是以上面的 A 依赖 B,B 依赖 A 为例。
在 B 进行属性注入,获取 A 对象时,会从三级缓存中先获取一个半成品 A,只有实例化,还没完成属性初始化的 A。这就打破了循环,解决循环依赖。
本文地址:https://blog.csdn.net/qq_32045991/article/details/107895530
如对本文有疑问, 点击进行留言回复!!
网友评论