Spring如何解决循环依赖问题

1. 什么是循环依赖?

        可以把它拆分成循环和依赖两部分来看,循环是指计算机领域中的循环,执行流程形成闭合回路;依赖就是完成这个工作的前提准备条件,和我们平常说的依赖大体上含义一致。放到Spring中来看就一个或多个Bean实例之间存在直接或间接的依赖关系,构成循环调用。

2. 循环依赖的类型

        2.1 自依赖,自己依赖自已从而形成循环依赖,一般情况不会发生这种,因为容易被发现。

Spring如何解决循环依赖问题_第1张图片

       2.2 直接依赖,发生再两个对象之间。比如:A依赖B,B又反过来依赖于A。

Spring如何解决循环依赖问题_第2张图片

        2.3 间接依赖,这种依赖发生在3个或者以上对象依赖场景。比如:A依赖B,B依赖于C,C依赖于A,可以想象当中依赖的对象很多时,是很难发现这种循环依赖的,一般都是需要借助一些工具排查。

Spring如何解决循环依赖问题_第3张图片

 3. Spring如何解决循环依赖的

            Spring通过三级缓存解决了循环依赖,其中:

        一级缓存:singletonObjects,单例池,用于保存实例化、属性赋值(注入)、初始化完成的bean实例;

        二级缓存:earlySingletonObjects,存放已创建的对象,但是未注入属性和初始化;

        三级缓存:singletonFactories,存放ObjectFactory对象。

        当A、B两个类发生循环引用时,在A完成实例化后,就使用实例化后的对象去创建一个对象工厂,添加到三级缓存中,如果A被AOP代理,那么通过这个工厂获取到的就是A代理后的对象,如果A没有被AOP代理,那么这个工厂获取到的就是A实例化的对象。

        当A进行属性注入时,会去创建B,同时B又依赖了A,所以创建B的同时又会去调用getBean(a)来获取需要的依赖,此时的getBean(a) 会从缓存中获取;

第一步:先获取到三级缓存中的工厂;

第二步:调用对象工厂的getObject方法来获取到对应的对象,得到这个对象后将其注入到B中。紧接着B会走完它的生命周期流程,包括初始化、后置处理器等。

第三步:当B创建完后,会将B再注入到A中,此时A完成它的整个生命周期。

 4. 为什么要使用三级缓存?二级缓存能解决循环依赖吗?

        如果要使用二级缓存解决循环依赖,意味着所有Bean在实例化后就要完成AOP代理,这样违背了Spring设计的原则,Spring在设计之初就是通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器在Bean生命周期的最后一步来完成AOP代理,而不是在实例化后就立马进行AOP代理。

你可能感兴趣的:(Spring,spring,java,前端)