一文清晰带你弄清楚Spring IOC 循环依赖问题是如何解决的

什么是循环依赖

循环依赖又被成为循环引用,即两个或者多个bean相互之间的持有对方,比如A 引用B,B引用C,C 又引用A,则它们最终反映为一个环,如下图所示:
在这里插入图片描述
循环依赖是对象之间的相互依赖关系,循环依赖就是一个死循环,除非有终结条件,否则就是死循环,最终导致内存溢出错误.

解决循环依赖

Spring 容器循环依赖包括构造器循环依赖和setter 循环依赖,prototype范围循环依赖.

构造器循环依赖处理

通过构造器注入构成循环依赖是无法解决的,只能抛出BeanCurrentlyInCreationException异常表示循环依赖,

setter循环或者@Autowired进行循环依赖处理

Spring 的循环依赖的理论依据基于java的引用传递,当获得对象的引用时,对象的属性是可以延后设置,但是构造器必须在获取引用之前.

Spring 通过setxxx 或者@Autowired 方法解决循环依赖其实是通过提前暴露一个ObjectFactory对象来完成,即ClassA 在调用构造器完成对象初始化之后,在调用ClassA 的setClassB方法之前就把ClassA 实例化的对象通过ObjectFactory提前暴露到Spring 容器职工.

Spring 容器初始化ClassA通过构造器初始化对象后提前暴露到Spring 容器.

AbstractAutowireCapableBeanFactory.doCreateBean()方法中提前暴露初始化对象的源代码如下:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

ClassA 调用setClassB方法,Spring 首先尝试从容器获取ClassB ,此时ClassB 不存在Spring容器中,Spring容器初始化B,同时也会将ClassB提前暴露到Spring容器中,ClassB调⽤setClassA⽅法,Spring从容器中获取ClassA ,因为第⼀步中已经提前暴露了ClassA,因此可以获取到ClassA实例.ClassA通过spring容器获取到ClassB,完成了对象初始化操作。这样ClassA和ClassB都完成了对象初始化操作,解决了循环依赖问题。

prototype范围循环依赖处理

对于原型bean的初始化过程中无论是通过构造器参数循环依赖还是通过setter方法产生循环依赖,Spring 都会直接报错处理.
在AbstractBeanFactory.doGetBean()⽅法中是这样对prototype范围循环依赖进行处理的:
在这里插入图片描述
判断是否是prototype循环依赖:
在这里插入图片描述
若是prototype循环依赖直接抛出BeanCurrentlyInCreationException异常:

在这里插入图片描述
当scope="prototype"时,在获取bean之前如果这个原型bean正在被创建则直接抛出异常,原型bean 在创建之前进行标记这个beanName正在被创建,等创建结束之后会被删除标记.
在这里插入图片描述
从源码可以得出这样一个结论: Spring 不支持原型bean的循环依赖.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

弯_弯

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

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

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

打赏作者

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

抵扣说明:

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

余额充值