一 spring为什么要使用多级缓存
首先清楚spring中bean 的加载过程:
1 解析需要spring管理的类为beanDefinition
2 通过反射实例化对象
3 反射设置属性
4初始化,调用initMethod等。(postConstruct也是在这执行)
循环依赖的问题: a依赖b,b依赖a。
在a实例化之后会先将a放入到缓存中,然后给a设置属性,去缓存中查到b。此时找不到就开始b的创建。b实例化之后,放入到缓存中,需要给a设置属性,此时去缓存中查到a设置成功。然后初始化。成功后将b放入一级缓存。这个时候a在给自己属性b设置值的时候就找到了b,然后设置b。完成属性设置,再初始化,初始化后a放入一级缓存。
二 为什么要使用三级缓存
解决代理对象(如aop)循环依赖的问题。
例: a依赖b,b依赖a,同时a,b都被aop增强。
首先明确aop的实现是通过 postBeanProcess后置处理器,在初始化之后做代理操作的。
为什么使用三级缓存原因:
1 只使用二级缓存,且二级缓存缓存的是一个不完整的bean
如果只使用二级缓存,且二级缓存缓存的是一个不完整的bean,这个时候a在设置属性的过程中去获取b(这个时候a还没有被aop的后置处理器增强),创建b的过程中,b依赖a,b去缓存中拿a拿到的是没有经过代理的a。就有问题。
2 使用二级缓存,且二级缓存是一个工厂方法的缓存
如果二级缓存是一个工厂的缓存,在从缓存中获取的时候获取到经过aop增强的对象。可以看到从工厂缓存中获取的逻辑。
protected ObjectgetEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bpinstanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
a依赖b,b依赖a,c。c又依赖a。a,b,c均aop增强。
加载开始: a实例化,放入工厂缓存,设置b,b实例化,设置属性,拿到a,此时从工厂缓存中拿到代理后的a。由于a没加载完毕,不会放入一级缓存。这个时候b开始设置c,c实例化,设置属性a,又去工厂缓存中拿对象a。这个时候拿到的a和b从工厂缓存不是一个对象。出现问题。
3 使用二级缓存,二级缓存缓存的是增强后的bean。这个与spring加载流程不符合。spring加载流程是:实例化,设置属性,初始化,增强。在有循环引用的时候,之前的bean并不会增强后放入到二级缓存。
综上1,2,3 可知二级缓存解决不了有aop的循环依赖。spring采用了三级缓存。
三 spring的三级缓存
一级缓存 singletonObjects 缓存加载完成的bean。
二级缓存 earlySingletonObjects 缓存从三级缓存中获取到的bean,此时里面的bean没有加载完毕。
三级缓存 singletonFactories 。缓存一个objectFactory工厂。
场景:a依赖b,b依赖a和c,c依赖a。并且a,b,c都aop增强。
加载过程:
a实例化,放入三级工厂缓存,设置属性b,b实例化放入三级缓存。b设置属性a,从三级工厂缓存中获取代理后的对象a,同时,代理后的a放入二级缓存,然后设置属性c,c实例化放入三级缓存,设置属性a,此时从二级缓存中获取到的代理后的a跟b中的a是一个对象,属性a设置成功。c初始化,然后执行后置处理器。进行aop的增强。增强后将代理的c放入到一级缓存,同时删除三级缓存中的c。c加载完成,b得到c,b设置c成功。b初始化,然后执行后置处理器,进行aop增强,将增强后的代理对象b放入到一级缓存。删除三级缓存中的b。此时 a拿到b,设置属性b成功,开始初始化,初始化后执行后置处理器。在aop的后置处理器中有一个以beanName为key,经过aop增强的代理对象为value的map earlyProxyReferences。
这个时候 后置处理器处理对象a的时候,
public ObjectpostProcessAfterInitialization(@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;
}
也就是 发现这个beanName已经被代理后就不在代理。这个时候执行后置处理器后,a还是未经代理的对象a。此时a再通过getSingleton 重新从缓存中获取一下a。
Object earlySingletonReference = getSingleton(beanName, false);
false 表示不从三级缓存中取,只从一级,二级缓存中获取。
这个时候能拿到二级缓存中的a。二级缓存中的a也是经过代理后的a。
然后将代理后的a放入到一级缓存中。a加载完毕。
放入一级缓存的过程 :
addSingleton(beanName, singletonObject);
从三级工厂缓存中获取对象:
protected ObjectgetEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bpinstanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
其中 AbstractAutoProxyCreator实现该接口。
public ObjectgetEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return wrapIfNecessary(bean, beanName, cacheKey);
}
wrapIfNecessary()就是真正执行代理的。
bean初始化之后执行的后置处理器:
其中AbstractAutoProxyCreator 实现了该接口。