栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring如何解决循环依赖问题

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring如何解决循环依赖问题

看到一篇文章讲Spring如何解决循环依赖问题,记录一下:

PS:其实正确答案是开发人员做好设计,别让Bean循环依赖,但是没办法,面试官不想听这个。

我们都知道,单例Bean初始化完成,要经历三步:

注入就发生在第二步,属性赋值,结合这个过程,Spring 通过三级缓存解决了循环依赖:

1、一级缓存 : Map singletonObjects,单例池,用于保存实例化、属性赋值(注入)、初始化完成的 bean 实例
2、二级缓存 : Map earlySingletonObjects,早期曝光对象,用于保存实例化完成的 bean 实例
3、三级缓存 : Map> singletonFactories,早期曝光对象工厂,用于保存 bean 创建工厂,以便于后面扩展有机会创建代理对象。

我们来看一下三级缓存解决循环依赖的过程:
当 A、B 两个类发生循环依赖时:

A实例的初始化过程:

1、创建A实例,实例化的时候把A对象⼯⼚放⼊三级缓存,表示A开始实例化了,虽然我这个对象还不完整,但是先曝光出来让大家知道

2、A注⼊属性时,发现依赖B,此时B还没有被创建出来,所以去实例化B

3、同样,B注⼊属性时发现依赖A,它就会从缓存里找A对象。依次从⼀级到三级缓存查询A,从三级缓存通过对象⼯⼚拿到A,发现A虽然不太完善,但是存在,把A放⼊⼆级缓存,同时删除三级缓存中的A,此时,B已经实例化并且初始化完成,把B放入⼀级缓存。

4、接着A继续属性赋值,顺利从⼀级缓存拿到实例化且初始化完成的B对象,A对象创建也完成,删除⼆级缓存中的A,同时把A放⼊⼀级缓存

5、最后,⼀级缓存中保存着实例化、初始化都完成的A、B对象

所以,我们就知道为什么Spring能解决setter注入的循环依赖了,因为实例化和属性赋值是分开的,所以里面有操作的空间。如果都是构造器注入的化,那么都得在实例化这一步完成注入,所以自然是无法支持了。

为什么二级缓存不行,必须三级缓存:

主要是为了⽣成代理对象。如果是没有代理的情况下,使用二级缓存解决循环依赖也是OK的。但是如果存在代理,三级没有问题,二级就不行了。

因为三级缓存中放的是⽣成具体对象的匿名内部类,获取Object的时候,它可以⽣成代理对象,也可以返回普通对象。使⽤三级缓存主要是为了保证不管什么时候使⽤的都是⼀个对象。

假设只有⼆级缓存的情况,往⼆级缓存中放的显示⼀个普通的Bean对象,Bean初始化过程中,通过 BeanPostProcessor 去⽣成代理对象之后,覆盖掉⼆级缓存中的普通Bean对象,那么可能就导致取到的Bean对象不一致了。

参考文献:https://mp.weixin.qq.com/s/Y17S85ntHm_MLTZMJdtjQQ

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/825478.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号