Spring使用三级缓存解决循环依赖

参考:
唯品会一面:Spring 为何需要三级缓存解决循环依赖,而不是二级缓存?
Spring解决循环依赖,你真的懂了吗?

三级缓存图解:

在这里插入图片描述

总结:

只适用于set注入方式,构造器不支持。

例子:假设A类有属性B,B类有属性A,AB循环依赖。

步骤:
1. A类先实例化,属性还没填充的时候会通过ObjectFactory将半成品的A类实例bean存储在三级缓存当中;
2. A类开始填充属性,填充B类属性,发现B类还没有实例化,因此会先去实例化B类;
3. 开始实例化B类,属性还没填充的时候也会通过ObjectFactory将半成品的B类实例bean存储到三级缓存当中;
4. B类开始填充属性,填充A类属性,这时候可以在三级缓存当中查找到A类的半成品ObjectFactory;
5. B类完成了属性填充,已经是一个完整的bean实例了,因此会被放入到一级缓存当中;
6. 接着A类也完成了属性填充,并且也被放入到一级缓存当中
以上,解决了循环依赖的问题。

PS:
在步骤3的时候,拿到了ObjectFactory时,调用ObjectFactory.getObject()方法,内部最终会调用getEarlyBeanReference()方法,
该方法的大概逻辑为:
1. 如果bean被AOP切面代理,则返回的是beanProxy对象
2. 如果未被代理,则返回的是原bean实例
这时,会把半成品bean实例从三级缓存移除,放到二级缓存当中。

缓存是从一级缓存、二级缓存、三级缓存顺序依次查询的,查到了则返回。

bean实例被添加到一级缓存的时候,会移除二级缓存、三级缓存的bean实例。

问题:为什么Spring不能解决构造器的循环依赖?
答案:在Bean调用构造器实例化之前,一二三级缓存并没有Bean的任何相关信息,在实例化之后才放入三级缓存中,因此当getBean的时候缓存并没有命中,这样就抛出了循环依赖的异常了。
	

猜你喜欢

转载自blog.csdn.net/weixin_43871678/article/details/114668933