面试题:Spring循环依赖问题

时间:2021-01-12 09:53:56   收藏:0   阅读:108

Spring是怎么解决循环依赖的?

首先,Spring 解决循环依赖有两个前提条件:

  1. 不全是构造器方式的循环依赖
  2. 必须是单例

基于上面的问题,我们知道Bean的生命周期,本质上解决循环依赖的问题就是三级缓存,通过三级缓存提前拿到未初始化的对象。

第一级缓存:用来保存实例化、初始化都完成的对象

第二级缓存:用来保存实例化完成,但是未初始化完成的对象

第三级缓存:用来保存一个对象工厂,提供一个匿名内部类,用于创建二级缓存中的对象

技术分享图片

假设一个简单的循环依赖场景,A、B互相依赖。

技术分享图片

A对象的创建过程:

  1. 创建对象A,实例化的时候把A对象工厂放入三级缓存

技术分享图片

  1. A注入属性时,发现依赖B,转而去实例化B

  2. 同样创建对象B,注入属性时发现依赖A,一次从一级到三级缓存查询A,从三级缓存通过对象工厂拿到A,把A放入二级缓存,同时删除三级缓存中的A,此时,B已经实例化并且初始化完成,把B放入一级缓存。

技术分享图片

  1. 接着继续创建A,顺利从一级缓存拿到实例化且初始化完成的B对象,A对象创建也完成,删除二级缓存中的A,同时把A放入一级缓存

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

技术分享图片

因此,由于把实例化和初始化的流程分开了,所以如果都是用构造器的话,就没法分离这个操作,所以都是构造器的话就无法解决循环依赖的问题了。

具体的方法:

技术分享图片

为什么要三级缓存?二级不行吗?

不可以,主要是为了生成代理对象。

因为三级缓存中放的是生成具体对象的匿名内部类,value为一个lambda表达式,他可以生成代理对象,也可以是普通的实例对象。

使用三级缓存主要是为了保证不管什么时候使用的都是一个对象。

假设只有二级缓存的情况,往二级缓存中放的显示一个普通的Bean对象,BeanPostProcessor去生成代理对象之后,覆盖掉二级缓存中的普通Bean对象,那么多线程环境下可能取到的对象就不一致了。

技术分享图片

原文:https://www.cnblogs.com/dalianpai/p/14265090.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!