三级缓存解决创建 Bean 过程中的循环依赖
1,什么是循环依赖?
即 A 依赖于 B,B 依赖于 C,C 依赖于 A。这样的问题导致 A 在实例化的时候永远都不能完成。
循环依赖的分类:
- 构造器循环依赖
这种情况无法解决。因为必须通过构造器实例化,不可能不去调用构造器,也就无法避免依赖的发生。此时抛出BeanCurrentlyInCreationException
。 - setter 循环依赖。可以通过将实例化和初始化分开的方式,提前暴露已经实例化好的 bean。
spring 只能解决 setter 情况下的单例 bean 的循环依赖问题:
/** Cache of singleton objects: bean name --> bean instance */ //一级缓存,存放成品对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name --> ObjectFactory *///三级缓存,存放函数式接口,完成代理对象的覆盖
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name --> bean instance *///二级缓存,存放半成品对象
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
private final Set<String> registeredSingletons = new LinkedHashSet<>(256); //已经创建成功的单例
2,循环依赖的分析
我们按照程序执行的过程,分析 spring 是如何解决循环依赖的。
我们知道在加载 spring 配置文件的过程中,会触发 refresh 方法。具体的:
在 AbstractBeanFactory#refresh()#finishBeanFactoryInitialization(beanFactory)
之中,会通过
getBean(beanName)
方法完成对象创建。这里即调用的是 doGetBean
,里面会首先调用 getSingleton(beanName)
方法:
//getSingleton(beanName) 调用的实际方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//首先从一级缓存 singletonObjects 中获取成品对象
Object singletonObject = this.singletonObjects.get(beanName);
//一级缓存为 null 且 bean 正在创建(循环依赖发生了,则触发二级缓存)
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//二级缓存中获取半成品对象
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//三级缓存中获取接口方法对象
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
//如果存在三级缓存,则将其加入二级缓存,再移除三级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
第一次创建是没有对象的,直接返回 null。此时会通过触发 getSingleton
的接口参数方法创建 bean:
getSingleton
的接口参数方法:这里的接口参数,也就是我们的三级缓存。此时三级缓存也是没有的,所以通过 createBean
创建。在该方法里会调用
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {//多例的处理逻辑,直接 createBean
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
getSingleton
的接口参数方法:这里的接口参数,也就是我们的三级缓存。此时三级缓存也是没有的,所以通过 createBean
创建。
思考为什么三级缓存存放的是接口方法,一个是我们利用该性质创建 bean,一个是以及增强。
然后他可以成功创建一个 Bean,并且如果这个 bean 是依赖的,可以通过 getEarlyBeanReference 实现代理 bean 的创建操作。此过程会对创建的 bean 使用代理 bean 进行覆盖。
//通过 ObjectFactory 获取实例
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
//一级缓存中获取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
beforeSingletonCreation(beanName);//标记创建中
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
//从三级缓存中获取,此时三级缓存不存在,所以会去创建一个
//此时会回调到 createBean#doCreateBean#createBeanInstance
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
//.....
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
//触发创建操作后,此处执行三级缓存机制(将 B 加入)
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
附:三级缓存机制:
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject); //加入一级缓存
this.singletonFactories.remove(beanName); //移除三级缓存
this.earlySingletonObjects.remove(beanName); //移除二级缓存
this.registeredSingletons.add(beanName); //标记已创建
}
}
创建 bean 之后属性赋值过程中会发生循环依赖。比如在创建 A 的过程中,要去实例 B,B 不存在则需要创建 B。创建 B 之后进行属性赋值又需要创建 A。此时 B 创建 A 的过程会先去二级缓存中拿到半成品的 A,这样便跳过了 A 的再次实例。B 拿到半成品的 A 后便完成了创建。也即此时 B 中有 a,a 中 b 为 null,因为 A 还是半成品,还没有属性赋值。
B 创建完毕,A 也就创建完毕了。
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//earlySingletonExposure 只有当支持循环依赖,才使用三级缓存,解决代理问题
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper); //填充属性,循环依赖发生
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
//....
if (earlySingletonExposure) {
//尝试从缓冲中获取
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
//这里需要说明的是,getEarlyBeanReference 是一个实现 aop 的增强方法,代理对象
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
//如果存在 BeanPostProcessors,需要代理,则生成代理对象
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
//拿到代理 bean 并覆盖,SmartInstantiationAwareBeanPostProcessor 会在实例化过程中进行增强操作
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
//轮询初始化 bean,但此时 bean 尚未实例化要知道
// Trigger initialization of all non-lazy singleton beans...
下一步轮询 bean,是否实现了 SmartInitializingSingleton 的增强操作
// Trigger post-initialization callback for all applicable beans...
总结
解决循环依赖问题,二级缓存即可实现。
三级缓存的使用可以解决代理 bean 的问题。
只要实现了 Aware 接口重写其 setxxxAware 方法后,就可以通过对象获得其属性。
动态代理的提现:拦截增强@lookup