本质上告诉你springbean注入为什么有些不能有循环依赖

本质上告诉你springbean注入为什么有些不能有循环依赖

网上有很多博主,要么就是表面的解释下死循环的不可行,要么就是搬出源代码分析为什么会抛出BeanInCreationException,
都没有从本质上解释spring为什么不能有循环依赖,循环依赖难道真的就因为感觉造成“死循环”,就认为任何地方不可以“循环依赖”了吗?
于是带着问题,不断翻阅资料,但是总是找不出为什么不能有循环依赖的解释,这才有了本质上的解决了心中的why冲动!以下就是我从本质上思考的一些心得把。

下面我用构造函数和属性注入两种方式,分别解释为什么循环依赖跟bean的模式,有些有关,有些又无关呢?

  1. .构造函数注入

    构造函数注入bean,不管单例还是原型,会构成循环依赖是因为:

<bean id="mixSingletonA"  class="ccc.spring.circulardependencies.constructor.A" lazy-init="true">
      <constructor-arg name="b" ref="mixPrototypeB"/> 
 </bean> 
 <bean id="mixPrototypeB"  class="ccc.spring.circulardependencies.constructor.B"  scope="prototype">
       <constructor-arg name="a" ref="mixSingletonA"/> 
 </bean> 

通过构造函数创建A时,大家都知道,必须先创建B,这时候创建一个B至少需要创建一个A,但注意,此时其实一个A都还没有创建呢,所以前面的B也创建不了啊,所以A,B就一直创建不了,如果更大的闭环,其实也是一个都创建不了了。
这里非常要注意,“至少一个”,这几个字眼,这是结合分析单例和原型模式了,还有就是它的原因是,因为一个都创建不了了,而不是什么“死循环”的原因了。其实有点像”死锁“的感觉,相互制约,谁都创建不了,所以也就不能创建bean了

2.属性注入

2.1 再说下setter注入,其中一个是原型模式,也不能有循环依赖的

<bean id="mixSingletonA"
    class="ccc.spring.circulardependencies.field.A" lazy-init="true">
        <property name="b" ref="mixPrototypeB"/> 
</bean> 
 <bean id="mixPrototypeB" class="ccc.spring.circulardependencies.field.B"
    scope="prototype">
   	    <property name="a" ref="mixSingletonA"/> 
  </bean>

如果是属性注入,先会创建完A,需要依赖B,然后再创建完B,发现又需要A,又需要创建好一个A,由于是prototype模式,是可以创建多个A,B的,结果又会创建B,创建完B,又要创建A…如此循环,根本就不会结束了,这才是真的死循环的原因。
这里要注意字眼,“创建完”,这里的意思就是已经创建好了,而不是将要创建,网上很多没有把这种先后顺序说清楚,导致不能理解构造注入和属性注入的区别。

如果是全是单例模式,为什么就不会了呢,因为,创建B不会再需要创建A了,直接取原来创建的A依赖进去就可以了,也就不会再创建A,继而创建B,一直下去,造成死循环了,所以,其实就是相比prototype模式,不会造成死循环。
至此就把spring框架为什么一定要解决这几种循环依赖的原因彻底说清楚了。一种构造函数实例化对象的机制造成的,一种是要达成prototype模式的设计目的造成的!
所以,这些都是在spring框架设计之初,就已经想好的。而不仅是spring组织是用代码来这样定义告诉我们就要这么用。而是spring组织也必须,遵循这样的java机制和设计,才能完善一个技术的实现规范,也就是实现这样一项定义,事先就需要想好它一些不能存在的场景,从而从设计和代码逻辑上面一开始就避免掉。因为如果是写好的代码运行再报错而不一开始就检测出来,无限个循环创建对象,早就把服务干死了!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值