Spring中的循环依赖问题

本文讲述了Spring框架中循环依赖的概念,如何通过三级缓存(单例池、早期单例和工厂缓存)来处理大部分循环依赖,以及二级缓存和三级缓存的作用。同时提到构造函数循环依赖的解决方法是使用懒加载。
摘要由CSDN通过智能技术生成

目录

什么是循环依赖?

解决循环依赖的方法


什么是循环依赖?

在 Spring 中,循环依赖指的是当两个或多个 Bean 彼此之间存在直接或间接的依赖关系,形成了一个闭环,导致 Spring 容器无法完成 Bean 的实例化和装配的情况。

循环依赖通常发生在以下情况下:

  1. 类之间的相互引用:如果两个类相互引用对方,例如 ClassA 中包含一个 ClassB 的成员变量,而 ClassB 中也包含一个 ClassA 的成员变量,就会形成循环依赖。

  2. 构造函数循环依赖:当两个或多个 Bean 的构造函数参数中相互依赖对方的 Bean 实例时,就会出现构造函数循环依赖。

Spring 框架通过使用三级缓存解决循环依赖问题。当创建 Bean 的过程中发现循环依赖时,Spring 会将正在创建的 Bean 实例提前暴露出来,暂时使用一个半初始化状态的 Bean 代替,待循环依赖的 Bean 创建完毕后再完成初始化和依赖注入。

尽管 Spring 提供了解决循环依赖的机制,但循环依赖通常被认为是一种设计上的缺陷,应尽量避免。因为循环依赖会增加代码的复杂性,降低代码的可读性和可维护性,可能导致程序运行时的死锁或其他不可预测的行为。因此,在设计应用程序时,应尽量避免出现循环依赖。

解决循环依赖的方法

Spring中通过三级缓存的方式可以解决大部分循环依赖问题

spring中的三级缓存指的是:

缓存名称源码名称作用
一级缓存singleonObjects单例池,缓存已经经历了完整的生命周期,已经初始化完成的bean对象
二级缓存earlySingleonObjects缓存生命周期还没有走完的bean对象
三级缓存singletonFactories缓存的是ObjectFactory,表示对象工厂,可以用来创建代理对象或普通对象

一级缓存作用:限制bean在beanFactory中只存在一份,及实现singleton scope,解决不了循环依赖问题

加入一级缓存的执行流程:

可以看到,一级缓存的加入并没有对解决循环问题起到什么作用,我们如果想要打破这个循环,就需要一个bean的中间对象,这个中间对象就是二级缓存。

加入二级缓存之后的执行流程:

可以看到,加入二级缓存之后,A对象在进行初始化的时候要去容器中注入B对象,此时容器中还不存在B对象,于是就将还没有初始化完的半成品A对象加入二级缓存中,转而去实例化B对象,在B对象初始化注入A对象的时候,在二级缓存中就可以得到A对象,于是循环就在这里被打破了,这里B对象就可以创建成功,将B对象存入一级缓存中,同时将B对象注入给A,A对象也创建成功,将A对象也出入一级缓存中,这样,对于普通对象产生的循环依赖问题我们就已经解决了。

不过二级缓存不能解决代理对象的循环依赖问题,那么我们就需要三级缓存。

加入三级缓存的执行流程如下:

ObjectFactory既可以创建普通对象,也可以创建代理对象。

那么是不是我们就不需要二级缓存了呢?

不是的,因为每次ObjectFactory每次都会创建一个新的对象,在从三级缓存中获取了一个对象的ObjectFactory创建一个对象实例之后,就将这个ObjectFactory移出三级缓存,将对象实例存入二级缓存之中,之后还是从二级缓存中得到这个bean对象,这样是保证了bean对象在生命周期中的单例性。

不过三级缓存解决不了构造方法出现循环依赖。

原因:由于bean的生命周期中构造函数是第一个执行的,spring框架并不能解决构造函数的依赖注入

解决方法:使用@Lazy进行懒加载,什么时候需要使用对象再进行bean对象的创建。

  • 13
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值