又读了一遍源码现在对三级缓存有了新的理解,才发现网上很多写的三级缓存相关的东西都是错的,包括我自己之前的第一篇,也有理解不准确的地方,这里我简单描述一下正确的理解过程。
但是还是建议在阅读上一篇彻底理解三级缓存和循环依赖文章之后,再对此文进行阅读。
三级缓存
singletonObjects 保存了所有完整的bean对象。
earlySingletonObjects 保存了调用过三级缓存中getEarlyBeanReference()的,且还未完全创建的bean对象。
singletonFactories 他是一个工厂的保存,目的是过去已经实例化的bean对象,但是在获取过程中,会对这些bean对象进行一些处理,处理方式如下
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
// 所有实现了SmartInstantiationAwareBeanPostProcessor接口的对象,调用其getEarlyBeanReference()方法。其实只有一个抽象类AbstratAutoProxyCreator实现了这个方法,也就是AOP操作。往earlyProxyReferences记录已经被AOP提前的bean对象,wrapIfNessary()方法去获取代理对象,是用CGlib还是用Proxy
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
所以总的来说,一级缓存用来保存完整的bean,二级缓存用来保存处理过AOP的bean,三级缓存用来获取bean,并实现AOP的提前。
为什么这么说,首先来看一下bean的创建过程,简化版如下。
依赖注入的过程是populate函数,然后调用selectCandidate()方法,通过beanName和类型去推断需要注入的bean,然后再去调用doGetBean方法。
然后getBean方法会去调用getSingleton()方法获取bean,这个方法如下。
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
简答来讲就是先从一级缓存中找,找不到再去二级缓存中找,找不到就去从三级缓存中找,如果是循环依赖,就能从在即缓存中找到这个工厂函数,并且调用,同时将这个bean放入二级缓存中,且从三级缓存中删除这个bean。然后拿到需要依赖的bean对象,可能是代理之后的bean对象,这里我们称其为被依赖bean,而依赖他的叫做原始bean。之后继续对原始bean做aware,beanPostProcessor和init操作,处理完后放入一级缓存。然后结束了,获取到这个bean。
这里主要讲一下为什么三级缓存用完之后要删除,然后放入二级缓存。
这个其实就关系到了二级缓存的主要作用,处理那些超过两个以上的循环依赖问题。例如A依赖B,B依赖A和C,C依赖A的情况,这个时候在beanB的创建过程中,首先从三级缓存中获取了A,并做了AOP提前,这时候C还没有创建,就要去创建C,而在C创建的过程中,又要去注入A,如果再用三级缓存区调用的话,就又会处理一次AOP导致报错,所以必须用一个缓存来记录那些已经AOP提前的,但是却还没有创建完成的,未放到一级缓存的。所以这里引入了一个二级缓存earlySingletonObjects.
其实命名的时候,确实也是下了工作,earlySingletonObjects,看名字也可以推断,是那些早期的,还未创建完全的bean对象的一个缓存。