Spring 循环依赖解决方案

1.Spring创建Bean主要分为两个步骤,创建原始Bean对象,接着去填充对象属性喝初始化。采用refresh()里面的11个修饰方法

2.每次创建bean之前,都会去缓存查看一下有没有该bean,因为是单例的,只能有一个。

3.当我们创建beanA的原始对象以后,并且把它放到三级缓存中,接下来就准备填充属性,这个时候发现依赖beanB,接着又去创建beanB
同样的流程,创建完beanB以后填充属性的时候又发现他依赖beanA又是同样的流程。

不同的是:
创建beanB的时候,这个时候可以再三级缓存中查询刚放进去的原始对象beanA(未填充数据的beanA),所以不需要继续创建,用它来注入beanB, 完成beanB的创建

既然beanB创建好了,放到一级缓存,所以刚放进去beanA就可以完成填充属性的步骤了,接着执行完剩下的逻辑,闭环完成,最终beanA喝beanB都在一级缓存中。

三级缓存流程:

查询流程:

spring boot三级缓存 spring三级缓存流程_spring boot三级缓存

Spring中解决循环依赖是依赖Bean的“中间态”这个概念,这个中间态指的是已经实例化了,但是还没有初始化状态---》俗称:半成品
实例化的过程又是通过构造器创建的,如果A没有创建好,是不可能提前曝光的,所以构造器的循环依赖无法解决。

但是Spring中为了解决单例下的循环依赖问题,使用了三级缓存。
一级缓存是单例池(singletoObjects)
二级缓存是提前曝光对象(earlySingletonObjects)
三级缓存是提前曝光工厂(singletoFactories)

假设A、B循环引用,实例化A的时候将其放入三级缓存中,接着填充属性,发现依赖了B,同样的流程也是实例化后将beanB放入三级缓存,
接着去填充属性的时候,发现了beanB依赖了A,这个时候从缓存中去查询早期暴露再工厂的A:

  • 没有AOP代理的化,直接将A的原始状态注入B,完成B的初始化后,接着属性填充和初始化,这个时候B已经完成,就去完成剩下A的步骤,
  • 有AOP代理的话,就进行AOP处理获取代理后的对象A,注入B,走剩下流程。