前言
咱们常常会被问到一个问题:Spring是如何解决循环依赖的问题的。 这个问题算是对于Spring的一个高频面试题,因为如果不刻意研读,置信即便读过源码,面试者也不肯定可能一下子思考出个中神秘。
本文次要针对这个问题,从源码的角度对其实现原理进行解说。
一、什么是循环依赖
多个bean之间相互依赖,造成了一个闭环。 比方:A依赖于B、B依赖于c、c依赖于A
通常来说,如果问spring容器外部如何解决循环依赖, 肯定是指默认的单例Bean中,属性相互援用的场景。也就是说,Spring的循环依赖,是Spring容器注入时候呈现的问题。
二、Spring如何解决循环依赖
1、Spring中单例Bean的三级缓存
第一级缓存〈也叫单例池)singletonObjects:寄存曾经经验了残缺生命周期的Bean对象
第二级缓存: earlySingletonObjects,寄存晚期裸露进去的Bean对象,Bean的生命周期未完结(属性还未填充残缺)
第三级缓存: Map<String, ObiectFactory<?>> singletonFactories,寄存能够生成Bean的工厂
2、Spring中Bean的生命周期
3、Bean初始化次要办法
getSingleton:心愿从容器外面取得单例的bean,没有的话
doCreateBean: 没有就创立bean
populateBean: 创立完了当前,要填充属性
addSingleton: 填充完了当前,再增加到容器进行应用
4、具体阐明
A创立过程中须要B,于是A将本人放到三级缓存外面,去实例化B
B实例化的时候发现须要A,于是B先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了A而后把三级缓存外面的这个A放到二级缓存外面,并删除三级缓存外面的A
B顺利初始化结束,将本人放到一级缓存外面(此时B外面的A仍然是创立中状态)而后回来接着创立A,此时B曾经创立完结,间接从一级缓存外面拿到B,而后实现创立,并将A放到一级缓存中。
5、图解
三、为什么应用三级缓存
1、应用一级缓存
实例化A->将半成品的A放入singletonObjects中->填充A的属性时发现取不到B->实例化B->从singletonObjects中取出A填充B的属性->将成品B放入singletonObjects->将B填充到A的属性中->将成品A放入singletonObjects。
问题:这种根本流程是通的,然而如果在整个流程进行中,有另一个线程要来取A,那么有可能拿到的只是一个属性都为null的半成品A,这样就会有问题。
2、应用二级缓存
a)应用singletonObjects和earlySingletonObjects
成品放在singletonObjects中,半成品放在earlySingletonObjects中
流程能够这样走:实例化A ->将半成品的A放入earlySingletonObjects中 ->填充A的属性时发现取不到B->实例化B->将半成品的A放入earlySingletonObjects中->从earlySingletonObjects中取出A填充B的属性->将成品B放入singletonObjects,并从earlySingletonObjects中删除B->将B填充到A的属性中->将成品A放入singletonObjects并删除earlySingletonObjects。
问题:这样的流程是线程平安的,不过如果A上加个切面(AOP),这种做法就没法满足需要了,因为earlySingletonObjects中寄存的都是原始对象,而咱们须要注入的其实是A的代理对象。
b)应用singletonObjects和singletonFactories
成品放在singletonObjects中,半成品通过singletonFactories来获取
流程是这样的:实例化A ->创立A的对象工厂并放入singletonFactories中 ->填充A的属性时发现取不到B->实例化B->创立B的对象工厂并放入singletonFactories中->从singletonFactories中获取A的对象工厂并获取A填充到B中->将成品B放入singletonObjects,并从singletonFactories中删除B的对象工厂->将B填充到A的属性中->将成品A放入singletonObjects并删除A的对象工厂。
问题:这样的流程也实用于一般的IOC,但如果A上加个切面(AOP)的话,这种状况也无奈满足需要,因为每次通过singletonFactories.getObject()获取的代理对象都不同。
参考:《2020最新Java根底精讲视频教程和学习路线!》
链接:https://juejin.cn/post/693974...