Spring 三级缓存主要是为了解决循环依赖问题,其中的三级缓存分别为:
1. 第一级缓存:成品对象缓存(SingletonObjects),存放经过完整 Bean 生命周期过程的单例 Bean 对象。
2. 第二级缓存:早期单例对象缓存(EarlySingletonObjects),存放没有经过完整 Bean 生命周期过程的单例 Bean 对象。
3. 第三级缓存:单例工厂缓存(SingletonFactories),存放的是一个 lambda 表达式,用于判断某个 Bean 是否会进行 AOP 操作。
循环依赖问题通常发生在单例作用域下的 Bean 之间,比如 A 类中有 B 对象,B 类中有 A 对象。在这种情况下,Spring 容器在实例化 Bean 时,会按照依赖关系进行。以下是三级缓存如何解决循环依赖的问题:
1. 当 A 类中的 B 对象还没有创建时,A 类首先被实例化。此时,A 类的构造函数还没有被调用,所以 A 类的属性还没有初始化。
2. Spring 容器发现 A 类中依赖 B 对象,但由于 B 对象尚未创建,容器无法将其注入到 A 类中。为了解决这个问题,Spring 容器会将 A 类的实例(未完成初始化)放入第二级缓存(EarlySingletonObjects)。
3. 接下来,B 类被实例化。同样,由于 B 类依赖 A 对象,而 A 对象尚未完全初始化,容器无法将 A 对象注入到 B 类中。此时,容器将 B 类的实例(未完成初始化)放入第二级缓存(EarlySingletonObjects)。
4. 然后,A 类和 B 类继续完成各自的初始化过程。在初始化过程中,它们会从第二级缓存中获取彼此的引用。尽管此时它们的属性可能还没有完全初始化,但它们已经相互依赖,不会再触发循环依赖问题。
5. 当 A 类和 B 类的初始化完成后,它们会被放入第一级缓存(SingletonObjects)。此时,循环依赖问题已经得到解决,因为两个 Bean 已经完成实例化并相互依赖。
通过三级缓存的设计,Spring 能够在实例化 Bean 时避免循环依赖问题。当两个 Bean 相互依赖时,它们会被放入第二级缓存,并在初始化过程中相互获取引用。一旦初始化完成,它们会被放入第一级缓存,从而解决问题。这种方法仅适用于单例作用域下的 Bean,对于原型作用域的 Bean,三级缓存机制不起作用。