Spring之三级缓存

本文目的

  1. Spring的三级缓存是什么?
  2. Spring的三级缓存它解决什么问题?
  3. Spring的三级缓存,为什么需要三级?

说明

一直知道三级缓存但未见其真容。今天就通过源码来解开这Spring三级缓存神秘的面纱😁。

Spring的三级缓存是什么?

从源码看就是三个Map

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry

一级缓存
/** 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);

Spring的三级缓存它解决什么问题?

从源码看三个Map各自内容如下:
一级缓存存放的是beanName->实例(已经初始好的了)
二级缓存存放的是beanName->实例(已经实例化但未初始化完)
二级缓存存放的是beanName->ObjectFactory(获取Object的工厂方法,lambda表达式)

从方法的注释可以知道这是这是获取bean的方法,而且还提到提早暴露是为了解决循环依赖问题 说明: 1、一级缓存不存在,若不在创建中则返回空,初次创建Bean时,若在创建中则走下一步 2、检查二级缓存,也不存在,当多个循环依赖时已经获取过会从三级升到二级时,如先经过A->B->A,再A->C->A 3、检查三级缓存 ,当是循环依赖时且都未创建则会进入这个逻辑如A->B->A

	/**
	 * Return the (raw) singleton object registered under the given name.
	 * <p>Checks already instantiated singletons and also allows for an early
	 * reference to a currently created singleton (resolving a circular reference).
	 * @param beanName the name of the bean to look for
	 * @param allowEarlyReference whether early references should be created or not
	 * @return the registered singleton object, or {@code null} if none found
	 */
	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	//一级缓存不存在,未初始化成功则不会有
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
		//检查二级缓存,也不存在,当多个循环依赖时已经获取过会从三级升到二级时,如先经过A->B->A,再A->C->A
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
				//检查三级缓存  ,当是循环依赖时且都未创建则会进入这个逻辑如A->B->A
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

Spring的三级缓存,为什么需要三级?

有必要三级吗?从源码上看三级缓存存的是ObjectFactory(lambda表达式)也就是bean未实例化(代理类未实例化实际的类以及通过反射实例化,lambda是封装了遍历后置处理器可以进一步加工,代理类生成也就是这个时候)其实直接在产生ObjectFactory这步直接执行后放入二级缓存中也是可以的,但从性能分析如果没有循环引用这个二级缓存也不会被用到,最终在doCreateBean→initializeBean→applyBeanPostProcessorsAfterInitialization也有一段代码产生包装类的代码和三级缓存中的ObjectFactory是一样的都是遍历后缀处理器处理,而代理处理类(想要验证需要开启AOP不然不会有该处理类)是一样的(org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator实现类是org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator)所调用的方法内容是差不多的逻辑是等价的

		protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
			......
				// Eagerly cache singletons to be able to resolve circular references
				// even when triggered by lifecycle interfaces like BeanFactoryAware.
				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));
				}

				// Initialize the bean instance.
				Object exposedObject = bean;
				try {
					populateBean(beanName, mbd, instanceWrapper);
					生成bean里面的applyBeanPostProcessorsAfterInitialization可能会产生代理类
					exposedObject = initializeBean(beanName, exposedObject, mbd);
				}
			......
			}
ObjectFactory实现bean的创建
	/**
	 * Obtain a reference for early access to the specified bean,
	 * typically for the purpose of resolving a circular reference.
	 * @param beanName the name of the bean (for error handling purposes)
	 * @param mbd the merged bean definition for the bean
	 * @param bean the raw bean instance
	 * @return the object to expose as bean reference
	 */
	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;
	}
	
	代理类AbstractAutoProxyCreator
	 public Object getEarlyBeanReference(Object bean, String beanName) {
        Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
        this.earlyProxyReferences.put(cacheKey, bean);
        return this.wrapIfNecessary(bean, beanName, cacheKey);
    }
正常bean创建
	/**
	 * Apply {@link BeanPostProcessor BeanPostProcessors} to the given existing bean
	 * instance, invoking their {@code postProcessAfterInitialization} methods.
	 * The returned bean instance may be a wrapper around the original.
	 * @param existingBean the existing bean instance
	 * @param beanName the name of the bean, to be passed to it if necessary
	 * (only passed to {@link BeanPostProcessor BeanPostProcessors};
	 * can follow the {@link #ORIGINAL_INSTANCE_SUFFIX} convention in order to
	 * enforce the given instance to be returned, i.e. no proxies etc)
	 * @return the bean instance to use, either the original or a wrapped one
	 * @throws BeansException if any post-processing failed
	 * @see BeanPostProcessor#postProcessAfterInitialization
	 * @see #ORIGINAL_INSTANCE_SUFFIX
	 */
	Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException;
			
	实现类 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
		@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}
	
	代理类AbstractAutoProxyCreator
	  public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
            //如果是循环依赖,这里会进不去因为getEarlyBeanReference会set一个一样的bean
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                return this.wrapIfNecessary(bean, beanName, cacheKey);
            }
        }

        return bean;
    }

🤗 总结归纳

目的是用于解决循环依赖但其实二级也能解决为了延迟初始化而设计三级缓存,减少非循环依赖时无需初始化三级缓存的ObjectFactory,从而减少性能开销和内存占用;还有另一个原因是后置处理器目的是在初始化后再执行这是Spring的设计原则(生命周期)但我没找到有力证明(感觉更像是后期拓展有不想将拓展内容和原因逻辑过多偶尔和设计的)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值