Spring三级缓存
场景
一直以为在Spring中出现循环依赖是个无解的问题,只能重新梳理bean之间的依赖关系避免形成循环依赖。今天突然发现ServiceA依赖了ServiceB,而ServiceB又依赖了ServiceA,但是服务却可以正常运行。这么看来,Spring是解决了循环依赖问题?一番搜索发现Spring使用了名为三级缓存的东西来解决循环依赖问题,简单记录下原理。
源码
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
- singleObjects:完成初始化的单例对象的cache,这里的bean经历过实例化->属性填充->初始化,以及各种后置处理。(一级缓存)
- earlySingleObjects:存放原生的bean对象(完成实例化但尚未进行属性填充及初始化),仅仅作为指针提前曝光,被其他bean引用。(二级缓存)
- singlefactories:在bean实例化之后,属性填充及初始化之前,如果允许提前曝光,Spring会将实例化之后的bean提前曝光,也就是把该bean转换为beanFactory并加入到singlefactories。(三级缓存)
- AbstractBeanFactory#doGetBean,使用getSingleton(beanName)获取到bean实例。
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//尝试从一级缓存获取
Object singletonObject = this.singletonObjects.get(beanName);
//获取不到并且bean正在创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//二级缓存获取
singletonObject = this.earlySingletonObjects.get(beanName);
//二级缓存也没用并且允许获取早期引用
if (singletonObject == null && allowEarlyReference) {
//三级缓存获取ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//获取bean实例
singletonObject = singletonFactory.getObject();
//放入二级缓存
this.earlySingletonObjects.put(beanName, singletonObject);
//从三级缓存删除
//也就是说,对于一个单例bean,ObjectFactory#getObject只会调用一次
//获取到早期bean之后,把这个bean实例从三级缓存升级到二级缓存
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
- 可以看到二级缓存中的bean是在getSingleton方法中put进去的,所以创建bean实例之后先是放到了三级缓存。在第一点中从三级缓存中仍有可能未获取到bean,此时会调用另一个getSingleton方法,它的入参有一个lambda。
可以看到这个方法在一级缓存中获取不到bean时,会调用外部传入的lambda,即第三点的createBean逻辑。
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 {
//调用外部传入的lambda,即下面第3点的createBean逻辑
//获取完成实例化的bean
//此时bean的实例已经存在于二级或三级缓存
//未出现循环依赖的情况,bean的实例一直在三级缓存,出现循环依赖的情况,将bean实例从三级缓存升级到二级缓存
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
//因为createBean逻辑中进行了initializeBean操作,所有此时相当于已经新初始化了一个单例bean,加入一级缓存
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
- 现在来看AbstractAutowireCapableBeanFactory#createBean方法,这里最终调用的是该类的doCreateBean方法。此时将bean加入到三级缓存,若出现循环依赖的情况则会从三级缓存升级到二级缓存,即1里面的逻辑。
//单例、允许循环依赖、正在创建
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//加入到三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
接着去执行了initializeBean初始化操作。
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
//初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
- 回到第二点的getSingleton方法,此时已经获取到了一个完成初始化的bean对象,将它加入一级缓存。
- 为什么需要三级缓存而不是二级缓存
还是在AbstractAutowireCapableBeanFactory#doCreateBean,initializeBean方法中,由于BeanPostProcessor的postProcessBeforeInitialization、postProcessAfterInitialization方法可能把创建的bean替换从而返回一个新对象。
回到第3点的addSingletonFactory方法,它的第二个参数就是一个ObjectFactory,这个ObjectFactory最终放入了三级缓存。其中提供了一个getEarlyBeanReference的埋点方法,通过这个埋点方法,它允许我们把需要替换的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;
//用了beanPostProcessor的一个埋点方法
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
Spring的AOP功能是通过生成动态代理类来实现的,我们最终使用的也是代理类而不是原始类实例。而代理类的创建就是在initializeBean方法的postProcessAfterInitialization埋点中。具体类为AbstractAutoProxyCreator。
//出现循环依赖的情况,getEarlyBeanReference会被先调用
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
//当前类放入earlyProxyReferences
this.earlyProxyReferences.put(cacheKey, bean);
//返回代理实例
return wrapIfNecessary(bean, beanName, cacheKey);
}
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
//出现循环依赖的情况,earlyProxyReferences中存放了当前类,因此不会返回代理对象
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
//没有出现循环依赖的情况,返回代理实例
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
其他
Spring对于属性注入(setter注入)的循环依赖问题,可以通过三级缓存来解决,但是它无法解决构造器注入的循环依赖,解决构造器注入的循环依赖可以通过@Lazy注解(延迟加载)。
Q.E.D.