Spring循环依赖问题

1 篇文章 0 订阅

Spring 产生循环依赖问题的前提条件

  1. Spring管理的Bean默认都是单例的,这些对象在Spring容器里面只有唯一一份,所以Spring创建bean的时候就必须要考虑到不能重复创建对象,否则也就违背了单例的原则,所以这个时候就需要考虑到循环依赖的情况

Spring解决循环依赖的思路

  1. Spring 是通过三级缓存Map,和一个registeredSingletons(标记缓存: 保存着正在创建中的对象的名称)来解决循环依赖的

Spring创建对象的两个阶段

  1. 对象的实例化
  2. 对象属性的注入(注入阶段会引起循环依赖)

Spring的三级缓存

  1. 一级缓存:保存所有已经创建完成的bean
    • private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256)
  2. 二级缓存:保存正常创建中的bean(完成了实例化,但是还未完成属性注入)
    • private final Map<String, Object> earlySingletonObjects = new HashMap<>(16)
  3. 三级缓存:保存的是ObjectFactory类型的对象的工厂,通过工厂的方法可以获取到目标对象
    • private final Map<String, ObjectFactory<?>> singletonFactoies = new HashMap<>(16)
  4. 标记缓存:保存着正在创建中的对象名称

为什么需要三个缓存而不是两个缓存

  1. 可以通过第三级Map的value属性作为参考,存放的是ObjectFactory对象
  2. ObjectFactory对象在调用getObject的时候,会(需要)处理代理类的包装和替换
  3. 即第三级缓存中还存在不确定性,所以需要三级

Spring无法解决循环依赖的场景

  1. 因为二级缓存中存放的是完成了实例化的对象,完成了实例化的对象放入二级缓存是解决循环依赖不可缺少的一环,但是对象的实例化是通过调用构造函数实例化的(即构造和注入放到一起的时候),所以如果是通过构造函数进行DI且有循环依赖的情况的话,Spring是无法解决的
  2. 类中有@Async注释的方法的话,Spring也无法解决循环依赖问题,原因是对于定义了Async方法的场景,Spring会新增一个后置处理器AsyncAnnotationBeanPostProcessor,其生成的代理对象和前面的对象不同,并且该后置处理器的顺序偏后
  3. @Lazy注解可以解决上述的两种循环依赖问题,其原理是Lazy修饰的属性,Spring会先为其创建一个代理对象而不是一个原始对象
    1. https://blog.csdn.net/WX10301075WX/article/details/123904543
    2. https://blog.csdn.net/yxh13521338301/article/details/117450763

无法解决循环问题场景的总结

  1. 无法进行实例化(如构造方法DI场景)
  2. 由于代理类与加载滞后的问题所引发的,拿不到同一个对象而照成的情况

最终总结

从SpringBoot 2.6.0 之后Spring官方已经不建议循环依赖了,从业务或者说包、Service类划分上去解决循环依赖才是一个相对正规的路径

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值