Spring循环依赖问题如何解决?(*)

本文深入探讨了Java中循环依赖的概念,展示了构造器依赖和setter注入两种情况,并详细解释了Spring在处理这两种情况时的区别。通过一个具体的例子,解释了Spring如何通过三级缓存解决单例模式下的循环依赖问题,同时指出在原型模式下循环依赖会导致错误。最后,提出了避免循环依赖的建议和解决循环依赖的原理。
摘要由CSDN通过智能技术生成

1.序言
什么是循环依赖?
怎么解决循环依赖?
解决方式的原理是什么?

2.什么是循环依赖?
上一段最直观的代码吧!

public class A {
    public A() {new B();}
}
 
public class B {
    public B() {new A();}
}
 
public static void main(Stirng[] args) {
    new A();
}

看到了吧,这就是循环依赖!即A类构造器中返回一个B类的实例,B类构造器中返回一个A类的实例!
简单来说,就是你中有我,我中有你!

但是除了上述的构造器依赖,还有一种依赖方式,及set属性注入的依赖方式。

public class AService {
  private BService b;
 
  public void setB(Bservice b) {
    this.b = b;
  }
}
 
public class BService {
  private AService a;
 
  public void setA(Aservice a) {
    this.a = a;
  }
}
 
<bean id="aService" class="com.ssm.TestApplication.AService">
    <property name="b" ref="bService"/>
</bean>
 
<bean id="bService" class="com.ssm.TestApplication.BService">
    <property name="a" ref="aService"/>
</bean>

此时,如果你使用第一段构造器方式的代码运行的话,就会报错如下:

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException:  
    Error creating bean with name 'a': Requested bean is currently in creation: Is there an unresolvable circular reference? 

报错原因:

  1. Spring首先注入 AService 是首先会将该Bean的name放入inCreationCheckExclusions 和 singletonsCurrentlyInCreation中 ,当注入时发现有一个 b属性,然后会就会到IOC中查找 Bservice 的引用

  2. 若有Bservice引用则直接赋值给b属性,否则会去创建BSerivce 这个Bean,在本例中由于是IOC初始化所以会去实例化BSerivce.

  3. 当去实例化BService时,发现有个 a属性,然后就又会去查找 AService引用,由于第一步还没有结束,所以IOC是没有ASerivce的。然后去尝试注入AService,但是Spring注入前有一个对inCreationCheckExclusions 和 singletonsCurrentlyInCreation有一个校验,会判断这两个缓存中是否包含 ASerivce的beanName。若有则直接抛异常。

个人理解就是:A实例还没有实例化完成并进入到spring的IOC容器中,所以B实例在实例化时,找不到A类的实例,就报错了!

但是如果,使用第二段代码的方式,再运行,就不会报错。纳尼?

小盆友,你是否有很多问号?
但是,各单位注意!
如果你在类上使用@prototype注解或是在配置文件bean配置中,使用scope=“prototype”,那么你就完蛋啦!
你会发现,第二段代码的方式,也会报错了!
不要急,咱们一路向北。。

3.如何解决循环依赖?
解决方式,其实上面已经提前告知了!

说说我个人的想法吧!

第一种,尽量避免使用循环依赖的方式获取要用到的对象。我不用,你怎么错。

第二种,使用单例的set属性注入的方式,来注入依赖对象。

4.解决循环依赖的方式的底层原理是什么?
下面来扒一扒为什么我上面说的第二钟解决方案可以避免循环依赖报错呢?原理为何?

这里我们需要了解两个点:

spring中bean的生命周期 和 spring三级缓存

在我们使用第二种解决方式时,spring创建A或B实例对象时,其实是提前通过三级缓存将依赖的对象实例存入了spring容器当中,所以在循环依赖时,不存在找不到对象实例而报错了 !但是,有一点需要注意,三级缓存获取对象时,是要先执行构造器方法的,所以这也就是为什么构造器方式的循环依赖会报错!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值