一、Spring 三级缓存
1、三级缓存的定义
看源码的DefaultSingletonBeanRegistry中有三个Map对象,通常情况下,称singletonObjects为一级缓存,earlySingletonObjects为二级缓存,singletonFactories 为三级缓存。
等级 | 名称 | 说明 |
---|---|---|
一级 | singletonObjects | 可以理解为单例池 |
二级 | earlySingletonObjects | 早期单例对象缓存 |
三级 | singletonFactories | 单例工厂缓存 |
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/** Cache of singleton objects: bean name to bean instance. */
//一级缓存:单例对象缓存池,beanName->Bean,其中存储的就是实例化,属性赋值成功之后的单例对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
//三级缓存:单例工厂的缓存,beanName->ObjectFactory,添加进去的时候实例还未具备属性
// 用于保存beanName和创建bean的工厂之间的关系map,单例Bean在创建之初过早的暴露出去的Factory,
// 为什么采用工厂方式,是因为有些Bean是需要被代理的,总不能把代理前的暴露出去那就毫无意义了
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
//二级缓存:早期的单例对象,beanName->Bean,其中存储的是实例化之后,属性未赋值的单例对象
// 执行了工厂方法生产出来的Bean,bean被放进去之后,
// 那么当bean在创建过程中,就可以通过getBean方法获取到
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);、
/** Names of beans that are currently in creation. */
//三级缓存是用来解决循环依赖,而这个缓存就是用来检测是否存在循环依赖的
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
}
2、三级缓存的作用
名称 | 作用 |
---|---|
singletonObjects | 存放初始化后的单例对象,也就是完成的bean对象 |
earlySingletonObjects | 存放实例化,未完成初始化的单例对象(未完成属性注入的对象),也是用来解决性能问题 |
singletonFactories | 存放ObjectFactory对象,存放的是工厂对象,主要用来解决循环依赖和aop的问题 |
3、为什么需要第三级缓存?
实际上使用二级缓存就能够实现循环依赖的解决,将二级缓存用来存放早期单例对象(半成品),然后一样的走生命周期的流程,也没有问题,为什么还需要三级缓存?
这个问题反映了spring设计的相当的精妙,如果说,注入的对象实现了aop功能,那么通过循环依赖注入其他bean的时候,bean是原始对象,也就是说没有经过aop的处理,不是最终的代理对象,需要通过三级缓存的ObjectFactory对象工厂才能解决aop的问题,才能获得最终需要的代理对象。
二、循环依赖是如何解决的
假设情景A依赖于B,B依赖于A
首先A通过getBean调到doCreateBean(Spring通过getBean方法获取bean),初步实例化即调用createBeanInstance()方法后,属性注入之前进入到下边代码中
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
//省略前面的部分代码
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 7.判断是否需要提早曝光实例:单例 && 允许循环依赖 && 当前bean正在创建中
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");
}
// 8.提前曝光beanName的ObjectFactory,用于解决循环引用
// 8.1 应用后置处理器SmartInstantiationAwareBeanPostProcessor,允许返回指定bean的早期引用,若没有则直接返回bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
// 初始化bean实例。
Object exposedObject = bean;
try {
// 9.对bean进行属性填充;其中,可能存在依赖于其他bean的属性,则会递归初始化依赖的bean实例
populateBean(beanName, mbd, instanceWrapper);
// 10.对bean进行初始化
//初始化bean,过程如下:
//1:判断是否实现了BeanNameAware,BeanClassLoaderAware,
// BeanFactoryAware方法,如果有,则设置相关的属性
//2: 调用bean初始化的前置(BeanPostProcessor)操作
//3: 执行初始化的方法。
// 如果有initializingBean,则调用afterPropertiesSet
// 如果有InitMethod,则调用初始方法
//4: 调用bean初始化的后置(BeanPostProcessor)操作
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
//省略中间的部分代码
// 13.完成创建并返回
return exposedObject;
}
}
属性注入之前Spring将Bean包装成一个工厂添加进了三级缓存中,即调用addSingletonFactory()方法
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
// 这里传入的参数也是一个lambda表达式,() -> getEarlyBeanReference(beanName, mbd, bean)
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
// 1.如果beanName不存在于singletonObjects缓存中
if (!this.singletonObjects.containsKey(beanName)) {
//往三级缓存里添加
// 2.将beanName和singletonFactory注册到singletonFactories缓存(beanName -> 该beanName的单例工厂)
this.singletonFactories.put(beanName, singletonFactory);
//清除此Bean在二级缓存里的缓存信息
// 3.移除earlySingletonObjects缓存中的beanName(beanName -> beanName的早期单例对象)
this.earlySingletonObjects.remove(beanName);
//这里为了记录注册单例的顺序
// 4.将beanName注册到registeredSingletons缓存(已经注册的单例集合)
this.registeredSingletons.add(beanName);
}
}
}
}
这里只是添加了一个工厂(通过这个工厂(ObjectFactory)的getObject方法可以得到一个对象),执行工厂的getObject相当于执行getEarlyBeanReference。那么,什么时候会去调用这个工厂的getObject方法呢?
当A开始属性注入,B开始实例化时,同样会通过getBean,同样会跟A一样属性注入,再次实例化A,此时再次实例化A时,getBean经过getSingleton会从三级缓存中拿出ObjectFactory,调用getObject会拿到A的对象。
到此为止,循环依赖被解决。
解决循环依赖后,会在doCreateBean()方法中调用populateBean()方法填充属性,完成对bean的依赖属性进行注入(@Autowired)。
即在AbstractBeanFactory类中:
通过 getBean(String name)方法、调用doGetBean()方法、在doGetBean()方法内部调用
Object sharedInstance = getSingleton(beanName);
代码,在getSingleton()方法中会从三级缓存中拿出ObjectFactory通过ObjectFactory单例对象工厂创建的单例对象,放到早期单例对象缓存中即二级缓存earlySingletonObjects,并在三级缓存中移除beanName对应的单例对象工厂
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
//一级缓存:单例对象缓存池,beanName->Bean,其中存储的就是实例化,属性赋值成功之后的单例对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//三级缓存:单例工厂的缓存,beanName->ObjectFactory,添加进去的时候实例还未具备属性
// 用于保存beanName和创建bean的工厂之间的关系map,单例Bean在创建之初过早的暴露出去的Factory,
// 为什么采用工厂方式,是因为有些Bean是需要被代理的,总不能把代理前的暴露出去那就毫无意义了
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
//二级缓存:早期的单例对象,beanName->Bean,其中存储的是实例化之后,属性未赋值的单例对象
// 执行了工厂方法生产出来的Bean,bean被放进去之后,
// 那么当bean在创建过程中,就可以通过getBean方法获取到
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
//三级缓存是用来解决循环依赖,而这个缓存就是用来检测是否存在循环依赖的
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 1.从单例对象缓存中获取beanName对应的单例对象
Object singletonObject = this.singletonObjects.get(beanName);
// 2.如果单例对象缓存中没有,并且该beanName对应的单例bean正在创建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//尝试给一级缓存对象加锁,因为接下来就要对缓存对象操作了
synchronized (this.singletonObjects) {
// 4.从早期单例对象缓存中获取单例对象(之所称成为早期单例对象,是因为earlySingletonObjects里
// 的对象的都是通过提前曝光的ObjectFactory创建出来的,还未进行属性填充等操作)
//尝试从二级缓存earlySingletonObjects这个存储还没进行属性添加操作的Bean实例缓存中获取
singletonObject = this.earlySingletonObjects.get(beanName);
// 5.如果在早期单例对象缓存中也没有,并且允许创建早期单例对象引用
//如果还没有获取到并且第二个参数为true,为true则表示bean允许被循环引用
if (singletonObject == null && allowEarlyReference) {
// 6.从单例工厂缓存中获取beanName的单例工厂
//从三级缓存singletonFactories这个ObjectFactory实例的缓存里尝试获取创建此Bean的单例工厂实例
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
//如果获取到工厂实例
if (singletonFactory != null) {
// 7.如果存在单例对象工厂,则通过工厂创建一个单例对象
singletonObject = singletonFactory.getObject();
// 8.将通过单例对象工厂创建的单例对象,放到早期单例对象缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
// 9.移除该beanName对应的单例对象工厂,因为该单例工厂已经创建了一个实例对象,并且放到earlySingletonObjects缓存了,
// 因此,后续获取beanName的单例对象,可以通过earlySingletonObjects缓存拿到,不需要在用到该单例工厂
this.singletonFactories.remove(beanName);
}
}
}
}
// 10.返回单例对象
return singletonObject;
}
}
循环依赖确实被解决了,但是从过程看,似乎ObjectFactory缓存没什么存在的必要?似乎singletonObjects和earlySingletonObjects已经可以解决依赖问题了?
那么三级缓存到底有什么作用呢?我们再仔细分析下singletonFactories
在doCreateBean()方法调用addSingletonFactory()方法,提前曝光beanName的ObjectFactory,用于解决循环引用的时候,会调用getEarlyBeanReference()方法,即addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
方法的时候
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
// 1.如果bean不为空 && mbd不是合成 && 存在InstantiationAwareBeanPostProcessors
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// 2.应用所有SmartInstantiationAwareBeanPostProcessor,调用getEarlyBeanReference方法
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
// 3.允许SmartInstantiationAwareBeanPostProcessor返回指定bean的早期引用
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
// 4.返回要作为bean引用公开的对象,如果没有SmartInstantiationAwareBeanPostProcessor修改,则返回的是入参的bean对象本身
return exposedObject;
}
}
它实际上就是调用了后置处理器的getEarlyBeanReference,而真正实现了这个方法的后置处理器只有一个,就是通过@EnableAspectJAutoProxy注解导入的AnnotationAwareAspectJAutoProxyCreator。也就是说如果在不考虑AOP的情况下,上面的代码等价于:
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
return exposedObject;
}
}
也就是说这个工厂啥都没干,直接将实例化阶段创建的对象返回了!所以说在不考虑AOP的情况下三级缓存有用嘛?讲道理,真的没什么用。
结合了AOP的循环依赖
上面已经说过了,在普通的循环依赖的情况下,使用二级缓存也能解决循环依赖,那么三级缓存就显得可有可无了。其实、三级缓存实际上跟Spring中的AOP相关,我们再来看一看getEarlyBeanReference的代码:
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
// 1.如果bean不为空 && mbd不是合成 && 存在InstantiationAwareBeanPostProcessors
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
// 2.应用所有SmartInstantiationAwareBeanPostProcessor,调用getEarlyBeanReference方法
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
// 3.允许SmartInstantiationAwareBeanPostProcessor返回指定bean的早期引用
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
// 4.返回要作为bean引用公开的对象,如果没有SmartInstantiationAwareBeanPostProcessor修改,则返回的是入参的bean对象本身
return exposedObject;
}
}
如果在开启AOP的情况下,那么就是调用到AnnotationAwareAspectJAutoProxyCreator的父类的AbstractAutoProxyCreator的getEarlyBeanReference方法,对应的源码如下:
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
// 如果需要代理,返回一个代理对象,不需要代理,直接返回当前传入的这个bean对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
wrapIfNecessary为Spring实现Bean代理的核心方法
- wrapIfNecessary在两处会被调用,一处是getEarlyBeanReference,另一处是postProcessAfterInitialization
- 在wrapIfNecessary方法内部调用getAdvicesAndAdvisorsForBean()返回匹配当前Bean的所有Advice\Advisor\Interceptor,用于判断此该类是否需要创建代理。
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
/**
* Spring实现Bean代理的核心方法。wrapIfNecessary在两处会被调用,一处是getEarlyBeanReference,
* 另一处是postProcessAfterInitialization
*/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
//已经被处理过
// 1.判断当前bean是否在targetSourcedBeans缓存中存在(已经处理过),如果存在,则直接返回当前bean
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
//不需要被织入逻辑的
// 2.在advisedBeans缓存中存在,并且value为false,则代表无需处理
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
//是不是基础的bean 是不是需要跳过的
// 3.bean的类是aop基础设施类 || bean应该跳过,则标记为无需处理,并返回
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
// 返回匹配当前Bean的所有Advice\Advisor\Interceptor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 5.如果存在增强器则创建代理
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//创建Bean对应的代理,SingletonTargetSource用于封装实现类的信息
// 5.1 创建代理对象:这边SingletonTargetSource的target属性存放的就是我们原来的bean实例(也就是被代理对象),
// 用于最后增加逻辑执行完毕后,通过反射执行我们真正的方法时使用(method.invoke(bean, args))
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// 5.2 创建完代理后,将cacheKey -> 代理类的class放到缓存
this.proxyTypes.put(cacheKey, proxy.getClass());
// 返回代理对象
return proxy;
}
//该Bean是不需要进行代理的,下次就不需要重复生成了
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
}
回到上面的例子,我们对A进行了AOP代理的话,那么此时getEarlyBeanReference将返回一个代理后的对象,而不是实例化阶段创建的对象,这样就意味着B中注入的A将是一个代理对象而不是A的实例化阶段创建后的对象。
三级缓存的意义何在?
就以我们上的A、B为例,其中A被AOP代理,我们先分析下使用了三级缓存的情况下,A、B的创建流程
假设不使用三级缓存,直接用二级缓存中,也是可以实现的,那么三级缓存搭配二级缓存的存在有什么意义呢?
上面两个流程的唯一区别在于为A对象创建代理的时机不同,在使用了三级缓存的情况下为A创建代理的时机是在B中需要注入A的时候,而不使用三级缓存的话在A实例化后就需要马上为A创建代理然后放入到二级缓存中去。对于整个A、B的创建过程而言,消耗的时间是一样的(所以常见的三级缓存提高了效率这种说法都是错误的)
上述这种情况下,差别就是在哪里创建代理。如果不用三级缓存,使用二级缓存,违背了Spring在结合AOP跟Bean的生命周期的设计!Spring结合AOP跟Bean的生命周期本身就是通过AbstractAutoProxyCreator这个后置处理器来完成的,在这个后置处理的postProcessAfterInitialization方法中对初始化后的Bean完成AOP代理。如果出现了循环依赖,那没有办法,只有给Bean先创建代理,但是没有出现循环依赖的情况下,设计之初就是让Bean在生命周期的最后一步完成代理而不是在实例化后就立马完成代理。
Spring Bean的生命周期:https://www.jianshu.com/p/620bc279e7a2
参考:
https://blog.csdn.net/qq_38762237/article/details/108468333