简介

说明

        本文介绍Spring(SpringBoot)为什么使用三级缓存来解决循环依赖(为什么不使用二级)。

问题引出

在上边的分析中我们可以提出两个问题:

  1. 二级缓存好像没有用到?那么它什么时候会用到?
  2. 为什么第三级缓存要用一个工厂,删除第三级缓存,只用第一二级不可以吗?

可以去掉第二级缓存吗?

简介

不可以去掉第二级缓存。

详解

假如有这种情况:a实例同时依赖于b和c,b和c都依赖于a。

        a实例化时,先提前暴露objectFactorya到三级缓存,调用getBean(b)依赖注入b实例。b实例化之后,提前暴露objectFactoryb到三级缓存,调用getBean(a)依赖注入a实例,由于提前暴露了objectFactorya,此时可以从三级缓存中获取到a实例, b实例完成了依赖注入,升级为一级缓存。a实例化再getBean(c)依赖注入c实例,c实例化之后,提前暴露objectFactoryc到三级缓存,调用getBean(a)依赖注入a实例,由于提前暴露了objectFactorya,此时可以从三级缓存中获取到a实例。注意这里又要从三级缓存中获取a实例,我们知道三级缓存中的实例是通过调用singletonFactory.getObject()方法获取的,返回结果每次都可能不一样。如果不用二级缓存,这里会有问题,两次获取的a实例不一样。

可以去掉第三级缓存吗?

概述

结论

不可以去掉第三级缓存。

原因

Spring 的设计原则是在 IOC 结束之后再AOP( bean 实例化、属性设置、初始化之后再通过进行AOP(生成代理对象))。即:AOP的实现需要与bean的生命周期的创建分离。

  1. 为了解决循环依赖但又尽量不打破这个设计原则的情况下,使用了第三级缓存(key:bean名字,value:ObjectFactory)。
  1. 前边分析过,它是将一个函数式接口作为ObjectFactory,相当于延迟初始化。AOP中发生循环依赖时,通过调用Object的getObject()方法获取到三级缓存中的对象。
  1. 如果去掉第三级缓存,将AOP的代理工作放到第二级缓存,这样的话,bean在创建过程中就先生成代理对象再初始化和其他工作,与Spring的AOP的设计原则相违背。

详解

        上边:“bean何时被加入第3级缓存?”  我们可以得到,第三级缓存里存放的value是:AbstractAutowireCapableBeanFactory#getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean)。

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}

可以看到实际调用SmartInstantiationAwareBeanPostProcessor接口的getEarlyBeanReference(Object bean, String beanName)方法,此接口有以下实现类:

Spring--循环依赖的原理(四)--为什么用三级缓存,而不是二级_缓存

InstantiationAwareBeanPostProcessorAdapter

@Override
public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
return bean;
}

直接返回bean,这里看起来第三级缓存没必要存在。但是,看另一个实现类:

AbstractAutoProxyCreator

@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}

这里把对象放入第二级缓存。

曾分析过AOP:将横切逻辑织入目标Bean:AbstractAutoProxyCreator#postProcessAfterInitialization方法,在Bean实例化之后被调用。

来看postProcessAfterInitialization

@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

把key对应的项从二级缓存中移除,如果原来二级缓存中就是这个bean,则返回此bean,否则,返回代理类。