Spring 在处理 循环依赖 时使用了 三级缓存机制,这是 Singleton Bean 创建过程中为了解决循环依赖的一种策略。通过三级缓存,Spring 可以提前暴露未完全初始化的对象,避免循环依赖导致的无限递归错误。
Spring IOC 容器的 三级缓存分为以下三个部分:
当遇到循环依赖时,Spring 会按照以下步骤来创建和管理 bean:
检查一级缓存:
singletonObjects
中查找,如果找到,说明这个 bean 已完全初始化,直接返回。检查二级缓存:
earlySingletonObjects
(二级缓存)中查找。检查三级缓存:
singletonFactories
(三级缓存)中获取一个对象工厂,调用工厂方法创建早期引用,并放入二级缓存。放入一级缓存:
singletonObjects
(一级缓存),并从二级、三级缓存中移除。假设存在以下两个类:A
和 B
,它们互相依赖。
class A {
private B b;
public A(B b) {
this.b = b;
}
}
class B {
private A a;
public void setA(A a) {
this.a = a;
}
}
在 Spring 容器中创建这两个对象时,会出现循环依赖:
A
,但 A
的构造器依赖 B
。B
,但 B
的 setA()
方法又依赖 A
。A
的引用提前暴露到二级缓存中。B
时,B
可以通过二级缓存获取 A
的引用,完成注入。A
和 B
都完成初始化,并分别存入一级缓存。Spring 的核心实现位于 DefaultSingletonBeanRegistry
类中。
// 从一级缓存中获取 bean
Object singletonObject = singletonObjects.get(beanName);
if (singletonObject == null) {
// 如果一级缓存没有,则尝试从二级缓存获取
singletonObject = earlySingletonObjects.get(beanName);
if (singletonObject == null) {
// 如果二级缓存也没有,则从三级缓存的 ObjectFactory 中获取
ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// 提前暴露到二级缓存中
earlySingletonObjects.put(beanName, singletonObject);
singletonFactories.remove(beanName);
}
}
}
return singletonObject;
适用于 Setter 注入:
不适用于构造注入:
三级缓存机制帮助 Spring 处理 Setter 注入 引发的循环依赖问题,但对于 构造器注入 的循环依赖为力。
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- kqyc.cn 版权所有 赣ICP备2024042808号-2
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务