Spring IoC循环依赖问题

Spring IoC循环依赖问题

文章内容输出来源:拉勾教育Java高薪训练营

什么是循环依赖

循环依赖其实就是循环引用,也就是两个或者两个以上的 Bean 互相持有对方,最终形成闭环。比如A 依赖于B,B依赖于C,C又依赖于A。

注意,这里不是函数的循环调用,是对象的相互依赖关系。循环调用其实就是一个死循环,除非有终结 条件。

Spring中循环依赖场景有:

  • 构造器的循环依赖(构造器注入)

  • Field 属性的循环依赖(set注入)

循环依赖处理机制

  • 单例 bean 构造器参数循环依赖(无法解决)
  • prototype 原型 bean循环依赖(无法解决)

对于原型bean(也就是多例bean)的初始化过程中不论是通过构造器参数循环依赖还是通过setxxx方法产生循环依 赖,Spring都会直接报错处理。

//AbstractBeanFactory.doGetBean()方法:
 
if (isPrototypeCurrentlyInCreation(beanName)) {
  throw new BeanCurrentlyInCreationException(beanName);
}

 
protected boolean isPrototypeCurrentlyInCreation(String beanName) { 
  Object curVal = this.prototypesCurrentlyInCreation.get(); 
  return (curVal != null &&(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
}

//在获取bean之前如果这个原型bean正在被创建则直接抛出异常。
//原型bean在创建之前会进行标记 这个beanName正在被创建,等创建结束之后会删除标记
try {
	//创建原型bean之前添加标记 beforePrototypeCreation(beanName);
	//创建原型bean
  prototypeInstance = createBean(beanName, mbd, args);
}
finally {
	//创建原型bean之后删除标记
  afterPrototypeCreation(beanName);
}

总结:Spring 不支持原型 bean 的循环依赖。

单例bean通过setxxx或者@Autowired进行循环依赖

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

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

  • ClassA调用setClassB方法,Spring首先尝试从容器中获取ClassB,此时ClassB不存在Spring 容器中。

  • Spring容器初始化ClassB,同时也会将ClassB提前暴露到Spring容器中

  • ClassB调用setClassA方法,Spring从容器中获取ClassA ,因为第一步中已经提前暴露了ClassA,因此可以获取到ClassA实例

    • ClassA通过spring容器获取到ClassB,完成了对象初始化操作。
  • 这样ClassA和ClassB都完成了对象初始化操作,解决了循环依赖问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值