循环依赖问题是指两个或多个 Bean 之间存在依赖关系,形成一个循环引用的情况。Spring 提供了一级缓存、二级缓存和三级缓存来解决不同情况下的循环依赖问题。
单例对象中的set方法的循环依赖
-
一级缓存: 一级缓存是 Spring 容器中默认的缓存机制,用于存放完全初始化好的 Bean。但是,一级缓存无法解决循环依赖的问题,因为在循环依赖时,无法提前拿到完全初始化好的 Bean。
-
二级缓存: 二级缓存是用于解决循环依赖的关键。在调用
a.getBean()时,会先将a的半成品放入singletonFactories(二级缓存)中,然后调用a.setB()时,会先去二级缓存查找b的半成品,如果没有,再去调用b.getBean()。这样可以防止陷入死循环。 -
三级缓存和工厂: 为了解决使用代理对象进行功能增强时的问题,引入了三级缓存
earlySingletonObjects和一个工厂。工厂的作用是创建代理对象或者原始对象。工厂创建对象的时机分为两种情况:- 有循环依赖,提前创建代理返回。
- 没有循环依赖,返回原始对象。
构造循环依赖问题
- 构造方法解决循环依赖: 在创建
a对象时,提供b的代理对象,并在b构造方法中注入a。这样a可以顺利初始化。调用b构造方法时,可以从一级缓存中取到a对象,顺利创建。 - ObjectFactory 解决构造循环依赖: 与第一种方法类似,唯一的不同之处在于,需要在
b的构造方法中注入一个ObjectFactory来起到推迟b的创建的作用。