spring中bean的循环依赖(纯理论)

一、循环依赖

1、什么是循环依赖?

多个Bean之间相互依赖,形成一个闭环。例如:A依赖B,B依赖A。

2、spring两种注入方式对循环依赖的影响

spring的两种注入方式分别是构造器注入setter注入

我们AB循环依赖问题只要A的注入方式是setter且singleton,就不会有循环依赖的问题。

bean的注入方式,如果是原型注入那么就会出现循环依赖异常的问题。

我们可以结合spring官网文档:docs.spring.io/spring-fram…

3、spring的三级缓存

在介绍三级缓存之前,我们先了解一下初始化与实例化。

实例化:单独的创建一个对象,也就是我们说的new一个对象,或者是spring的工厂生产一个对象,但是对象里面的属性还没有填充值的时候。

初始化:就是对象里的属性赋值的过程就是初始化。

这个三级缓存在DefaultSingletonBeanRegistry类里面了。

1)、一级缓存:存放已经经历完生命周期的bean对象。也就是这个对象已经实例化,且它的属性也进行了初始化。  相当于一个成品,可以直接用。

/** Cache of singleton objects: bean name --> bean instance */  private final Map<String, Object> singletonObjects = 
  new ConcurrentHashMap<String, Object>(256);
复制代码

2)、二级缓存:存放早起暴漏出来的bean对象。bean的生命周期没有结束(属性还没填充完)。就是创建完对象了,但是对象的属性还没有填充值。

/** Cache of early singleton objects: bean name --> bean instance */  private final Map<String, Object> earlySingletonObjects =   new HashMap<String, Object>(16);
复制代码

3)、三级缓存:存放可以生成bean的工厂。

/** Cache of singleton factories: bean name --> ObjectFactory */  private final Map<String, ObjectFactory<?>> singletonFactories = 
new HashMap<String, ObjectFactory<?>>(16);
复制代码

总结:只有单例的bean会通过三级缓存提前暴露来解决循环依赖的问题,

而非单例的bean,每次从容器中获取的都是一个新的对象,都会重新创建,所以非单例的bean是没有缓存的,不会将其放到三级缓存中。

4、三级缓存的四大方法

getSingleton:从一级缓存中获取单例的bean

doCreateObject:在三级缓存中创建一个单例bean

populateBean:给单例的bean的属性填充值

addSingleton:把单例的bean加到一级缓存中

5、A/B两个对象在三级缓存中迁移的说明(此过程可以中面试中解释三级缓存解决循环依赖的过程)

1)、在A创建过程中需要B,于是A将自己放到三级缓存里面,去实例化B

2)、B实例化的时候发现需要A,于是B先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了A,然后把三级缓存中的A迁移到二级缓存中,并删除掉三级缓存中的A

3)、此时B顺利初始化完毕,将自己放到一级缓存里(此时B里面的A依然是创建中状态)

然后回来接着创建A,此时B创建结束了,直接从一级缓存中拿到B,然后A创建完成,此时从二级缓存迁移到一级缓存,并删除二级缓存中的A。

Guess you like

Origin juejin.im/post/7047145074022416420