【Spring框架系列】Spring循环依赖问题如何解决?Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationExc

热门系列:


目录

  1.序言

  2.什么是循环依赖?

  3.如何解决循环依赖?

  4.解决循环依赖的方式的底层原理是什么?


1.序言

针对本篇博文的主题,咱们先来个无情拷问三连!!!

  • 什么是循环依赖?
  • 怎么解决循环依赖?
  • 解决方式的原理是什么?

一波三连,脑瓜子嗡嗡的吧。。。。。莫方,既来之,则安之。接着往下看!


2.什么是循环依赖?

上一段最直观的代码吧!!!看不懂的人,出门靠墙站10分钟再回来看!!

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.如何解决循环依赖?

解决方式,其实上面已经提前告知了!

说说我个人的想法吧!

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

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


4.解决循环依赖的方式的底层原理是什么?

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

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

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

具体说明,请看文末的参考链接。我就白话一下吧,因为我觉得能简单说明的道理,就不必搞的那么拗口了!!

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

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

善良勤劳勇敢而又聪明的老杨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值