|Spring循环依赖,我本来都不想写的,但网上好多错误观点



今天我们来盘 Spring 的经典面试题循环依赖 。
这的面试题很经典 , 网上相应的文章很多 , 但是我还是想写一下 , 因为有些文章的观点在我看来是错的 。
- 比如有构造器就无法解决循环依赖?
- 一定要三级缓存才能解决循环依赖?
- 到底为什么要三级缓存?
什么是循环依赖很简单 , 看下方的代码就知晓了
@Servicepublic class A { @Autowired
private B b;
@Servicepublic class B { @Autowired
private A a;
//或者自己依赖自己@Servicepublic class A { @Autowired
private A a;
上面这两种方式都是循环依赖 , 应该很好理解 , 当然也可以是三个 Bean 甚至更多的 Bean 相互依赖 , 原理都是一样的 , 今天我们主要分析两个 Bean 的依赖 。
这种循环依赖可能会产生问题 , 例如 A 要依赖 B , 发现 B 还没创建 。
于是开始创建 B, 创建的过程发现 B 要依赖 A ,而 A 还没创建好呀 , 因为它要等 B 创建好 。
就这样 它们俩就搁这卡 bug 了。
Spring 如何解决循环依赖上面这种循环依赖在实际场景中是会出现的 , 所以 Spring 需要解决这个问题 , 那如何解决呢?
关键就是 提前暴露未完全创建完毕的 Bean。
在 Spring 中 , 只有同时满足以下两点才能解决循环依赖的问题:
- 依赖的 Bean 必须都是单例
- 依赖注入的方式 , 必须 不全是 构造器注入 , 且 beanName 字母序在前的不能是构造器注入
所以 Spring 只支持单例的循环依赖 ,但是为什么呢 ?
按照理解 , 如果两个 Bean 都是原型模式的话 。
那么创建 A1 需要创建一个 B1 。
创建 B1 的时候要创建一个 A2 。
创建 A2 又要创建一个 B2 。
创建 B2 又要创建一个 A3 。
创建 A3 又要创建一个 B3.....
就又卡 BUG 了 , 是吧 , 因为原型模式都需要创建新的对象 , 不能跟用以前的对象 。
如果是单例的话 , 创建 A 需要创建 B , 而创建的 B 需要的是之前的个 A ,不然就不叫单例了 , 对吧?
也是基于这点 ,Spring 就能操作操作了 。
【|Spring循环依赖,我本来都不想写的,但网上好多错误观点】具体做法就是:先创建 A , 此时的 A 是不完整的(没有注入 B) , 用个 map 保存这个不完整的 A , 再创建 B, B 需要 A 。
所以从那个 map 得到“不完整”的 A , 此时的 B 就完整了 , 然后 A 就可以注入 B , 然后 A 就完整了 , B 也完整了 , 且它们是相互依赖的 。
读起来好像有点绕 , 但是逻辑其实很清晰 。
为什么不能全是构造器注入在 Spring 中创建 Bean 分三步:
- 实例化 , createBeanInstance , 就是 new 了个对象
- 属性注入 , populateBean ,就是 set 一些属性值
- 初始化 , initializeBean , 执行一些 aware 接口中的方法 , initMethod , AOP代理等
- 芯片|90%依赖进口,国内又一行业被“卡脖子”,比芯片垄断更严重
- 长治市DDZ精品内循环泵耐低温橡胶接头
- spring|纯白ITX来了,还支持GEAR 1高频内存!新款七彩虹B660迷你主板测试
- spring|iPhone14系列再次被确认:配色、屏幕、电池容量、价格基本清晰了
- 西宁市DFEG立式管道循环泵耐高温橡胶软接头
- 纸箱|可循环使用的快递箱亮相南京
- 高通骁龙|长虹也不肯闲着,研发新型空气循环扇,网友:空调市场压力倍增
- spring|安全管理框架,用Shiro还是用Spring Security?
- spring|这价格值得抢!锐龙7-6800H游戏本,配满血RTX3060高分屏6999元
- spring|微软明星产品Internet Explorer, IE浏览器在26岁时停止了更新
