spring三级缓存解决循环依赖原理
在Spring框架中,Bean的实例化和管理是通过其核心的IoC容器完成的。在处理Bean的依赖注入时,可能会遇到循环依赖的问题,即两个或多个Bean相互引用对方。为了解决这一问题,Spring采用了三级缓存机制。
一级缓存:singletonObjects
这是Spring IoC容器中的主要缓存,用于存放已经创建并完全初始化完毕的单例Bean。当一个Bean被请求时,Spring会首先从这个缓存中查找是否存在,如果存在则直接返回,避免了重复创建。
二级缓存:earlySingletonObjects
这是一个临时缓存,在Bean的创建过程中使用。当Bean的构造函数执行完毕,但尚未进行属性填充和初始化方法调用时,Bean会被暂时放入这个缓存中。这样,如果在这个阶段有其他Bean请求依赖于它,可以从这里获取到部分初始化的Bean实例,从而避免了循环依赖导致的异常。
三级缓存:singletonFactories
这是一个工厂缓存,存储的是Bean的Factory对象。当一个Bean正在被创建但还未完全初始化时,它的Factory对象会被放入这个缓存中。如果此时有其他Bean请求依赖于它,Spring会从这个缓存中获取Factory对象,并通过它来获取当前正在创建的Bean的一个部分初始化实例。
解决循环依赖的流程
- 当A依赖于B,B又依赖于A时,Spring在创建A的过程中,将A的Factory对象放入
singletonFactories
。 - 当B创建时,尝试从
singletonObjects
获取A,由于A尚未完全初始化,所以获取不到,然后从earlySingletonObjects
和singletonFactories
中查找。 - 从
singletonFactories
中找到A的Factory对象,通过它创建A的部分初始化实例,并将这个实例放入earlySingletonObjects
。 - B现在可以使用A的部分初始化实例继续其自身的初始化过程。
- 同样的逻辑应用于A对B的依赖。
- 当A和B都完成了初始化后,它们会被移出
earlySingletonObjects
,放入singletonObjects
,供后续的依赖注入使用。
按照以下步骤来描述这一过程:
-
开始创建Bean A:
- 检查
singletonObjects
缓存中是否已有Bean A的实例。 - 如果没有,开始实例化Bean A,并将Bean A的工厂对象放入
singletonFactories
缓存。
- 检查
-
实例化Bean A:
- 调用Bean A的构造器,创建Bean A的实例,但不填充依赖。
- 将创建的Bean A实例(部分初始化状态)放入
earlySingletonObjects
缓存。 - 标记Bean A为正在创建中。
-
解析Bean A的依赖:
- 当解析到Bean A依赖Bean B时,尝试从
singletonObjects
获取Bean B。 - 如果Bean B尚未创建,进入Bean B的创建流程。
- 当解析到Bean A依赖Bean B时,尝试从
-
开始创建Bean B:
- 检查
singletonObjects
缓存中是否已有Bean B的实例。 - 如果没有,开始实例化Bean B,并将Bean B的工厂对象放入
singletonFactories
缓存。
- 检查
-
实例化Bean B:
- 调用Bean B的构造器,创建Bean B的实例,但不填充依赖。
- 将创建的Bean B实例(部分初始化状态)放入
earlySingletonObjects
缓存。 - 标记Bean B为正在创建中。
-
解析Bean B的依赖:
- 当解析到Bean B依赖Bean A时,不从
singletonObjects
获取,而是从earlySingletonObjects
获取Bean A的早期引用。
- 当解析到Bean B依赖Bean A时,不从
-
继续创建Bean B:
- 使用从
earlySingletonObjects
中获取的Bean A的早期引用,完成Bean B的依赖填充。 - 完成Bean B的初始化,包括调用初始化方法等。
- 将完全初始化的Bean B放入
singletonObjects
缓存,并从earlySingletonObjects
和singletonFactories
中移除Bean B的条目。
- 使用从
-
继续创建Bean A:
- 使用从
earlySingletonObjects
中获取的Bean B的早期引用,完成Bean A的依赖填充。 - 完成Bean A的初始化,包括调用初始化方法等。
- 将完全初始化的Bean A放入
singletonObjects
缓存,并从earlySingletonObjects
和singletonFactories
中移除Bean A的条目。
- 使用从
-
结束:
- 此时,Bean A和Bean B都已经完全初始化,并存储在
singletonObjects
中,可以供其他Bean依赖使用。
- 此时,Bean A和Bean B都已经完全初始化,并存储在
通过这种方式,Spring能够优雅地处理循环依赖,确保Bean的正常创建和初始化。
收藏文章数量从多到少与“把书读薄”是一个道理