Spring 如何解决循环依赖?原型模式,构造器是否解决?

面试中常见Spring的面试题系列:Spring 如何解决循环依赖?

通常大部分人能说出来通过三级缓存来处理的。但如果深入点问,三级缓存的流程以及能否改为二级或者一级缓存处理 就无法说的很明白。

先来放一张图来举例循环依赖的场景:

代码示例:spring-learn: spring学习示例程序

也可以直接下载本地运行:spring-learn.zip-Java文档类资源-CSDN下载

代码示例目前采用的是xml+setter注入;后面增加field和构造器注入示例。

大致步骤为:

  1. 对象A进行实例化;
  2. 对象A实例化过程中,添加到单例工厂中;
  3. 对象A进行属性填充;
  4. 对象A属性填充处理ref=teacher的属性时确定需要依赖对象B;
  5. 对象B进行实例化;
  6. 对象B实例化过程中,添加到单例工厂中;
  7. 对象B进行属性填充;
  8. 对象B属性填充处理ref=student的属性时确定需要依赖对象A;
  9. 对象B属性填充过程,
    1. 先从singletonObjects中查找对象A(半成品,未初始化)是否存在,
    2. 然后再从earlySingletonObjects查找对象A(半成品,未初始化)是否存在,
    3. 最后通过singletonFactories查找对象A(半成品,未初始化),查到之后进行保存到earlySingletonObjects中;
  10. 跟第9步骤一起;
  11. 对象B进行初始化操作;
  12. 返回到对象A第3步的操作继续进行
  13. 对象A进行初始化操作;
  14. 最后对象A和对象B的实例化、初始化操作都完成了。
     

最近遇到Spring循环依赖相关的面试问题

1、原型模式下,Spring支持循环依赖吗?

答案:不支持,原型模式不会缓存对应的bean实例,自然不会进行循环依赖的处理,具体需要看源码部分,Spring直接抛出异常。

Spring版本:5.2.8
代码跟踪:AbstractBeanFactory#doGetBean  265-269行

            // Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

2、构造器方式,Spring支持循环依赖吗?

答案:默认不支持,因为Spring循环依赖的处理是在属性填充阶段进行的,具体需要看源码部分,Spring直接抛出异常。

AbstractAutowireCapableBeanFactory#createBeanInstance构造器实例化,
ConstructorResolver#resolveAutowiredArgument解析构造器的参数,
AutowireCapableBeanFactory#resolveDependency解析依赖,

通过在构造器参数中标识@Lazy注解,Spring 生成并返回了一个代理对象是可以解决构造器循环依赖问题的。

Spring构造器注入循环依赖的解决方案是@Lazy,其基本思路是:对于强依赖的对象,一开始并不注入对象本身,而是注入其代理对象,以便顺利完成实例的构造,形成一个完整的对象,

这样与其它应用层对象就不会形成互相依赖的关系;当需要调用真实对象的方法时,通过TargetSource去拿到真实的对象[DefaultListableBeanFactory#doResolveDependency],然后通过反射完成调用。


 

------------欢迎各位留言交流,如有不正确的地方,请予以指正。【Q:981233589】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

_夜半钟声到客船

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

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

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

打赏作者

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

抵扣说明:

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

余额充值