Spring三级缓存解决循环依赖

58 篇文章 0 订阅
12 篇文章 0 订阅

 对于没有循环依赖的场景下的bean创建过程如下,直接看核心代码(隐掉了部分循环依赖的代码)

	protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {
        // 分别从三级缓存中查询是否已经有该bean
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
            // 对于非FactoryBean直接 return sharedInstance;
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
        else {
            // 缓存没有则开始创建
			// Create bean instance.
			if (mbd.isSingleton()) {
				sharedInstance = getSingleton(beanName, () -> {
					try {
						return createBean(beanName, mbd, args);
					}
					catch (BeansException ex) {
						destroySingleton(beanName);
						throw ex;
					}
				});
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}
    }

    return (T) bean;
}
	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {	
		synchronized (this.singletonObjects) {
            // 判断一级缓存是否存在
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
                // 在singletonsCurrentlyInCreation这个map中put,表示该bean正在创建中
                // 如果该bean已经在singletonsCurrentlyInCreation会报错
				beforeSingletonCreation(beanName);

				boolean newSingleton = false;
				try {
                    // 调用createBean方法开始创建
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					throw ex;
				}
				finally {
                    // 从singletonsCurrentlyInCreation移除
					afterSingletonCreation(beanName);
				}
                // 写入一级缓存,并从二三级缓存中移除
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

	protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
        // 反射newInstance实例一个空对象
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
            // 注入属性和其他AutoWire bean
			populateBean(beanName, mbd, instanceWrapper);

            // 调用初始化方法
            // 1、BeanFactoryAware等
            // 2、BeanPostProcessor.ProcesspostProcessBeforeInitialization
            // 3、afterPropertiesSet和自定义初始化方法
            // 4、BeanPostProcessor.postProcessAfterInitialization
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
            // 省略
            throw ex;
		}

		return exposedObject;
	}

创建Bean的核心步骤分三步,此后就是一个完整的bean

  • 1、实例化
  • 2、注入属性
  • 3、初始化

对于有循环依赖的情况,来分析一下,A依赖B,B依赖A的情况如何解决。spring通过提前暴露半成品bean来解决,半成品指的是实例化后还没有进行注入或初始化的bean。这就是二级缓存的作用,在实例化后先把对象放到缓存Map中,在A找B,B找A的时候,发现缓存中A已经有了,进而完成B的bean创建,解决循环依赖。但是也有条件,分析以下注入方式

1、构造器注入,A在实例化前,发现构造器参数B也是bean,先去实例化B,B则发现构造器参数A也是bean,先去实例化A,开始套娃,这样无解,只能是报错。

2、A构造器注入B,B则是set注入A,这样能行吗?可以,但是这取决于AB两个bean的加载顺序,

如果A先加载,A实例化前发现构造器参数B也是bean,先去实例化B,B实例化后注入属性A时,A还没有实例化,这无解报错。

如果B先加载,B实例化后提前暴露到二级缓存,注入属性A时发现也是bean,先去实例化A,A构造器参数B已经提前暴露,所以A可以实例化成功,然后继续完成A的创建,结束循环依赖。

3、对于都是set注入,这就是一般情况了,实例化都没问题,都可以提前暴露对象,皆大欢喜

三级缓存

上边我们的分析,二级缓存已经满足需求,但是spring是三级缓存,为什么呢?试想如果bean存在被代理的情况,我们提前暴露的对象应该是源bean还是proxy对象,毫无疑问,应该是proxy对象。

那我们知道正常情况下,代理是在第三阶段初始化的最后一步BeanPostProcessor.postProcessAfterInitialization中将对象代理,返回的是proxy对象,代码位置:AbstractAutoProxyCreator#postProcessAfterInitialization

那也就是说循环依赖要求我们将对象的代理步骤提前到了第一步之后第二步之前,先来看看源码,到底是如何操作的,还是doCreateBean方法,上边那段我隐掉了其中一段关于循环依赖的代码,spring在实例化之后注入之前,将对象放入了三级缓存中,三级缓存是个ObjectFactory,是个获取bean的途径

	protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// 实例化bean
        // 。。。
		Object bean = instanceWrapper.getWrappedInstance();
        
        // 如果是单例bean、并且允许循环依赖,则放入三级缓存
        // 这里的三级缓存不是bean实例,而是ObjectFactory,是一个获取bean的方法
		// 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) {
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			populateBean(beanName, mbd, instanceWrapper);
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}

		if (earlySingletonExposure) {
            // 这里的false表示只从前两级缓存中查找bean对象
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
                // 如果能查到,表示三级缓存的ObjectFactory被调用了,bean被转移到二级缓存,发生了循环依赖
				if (exposedObject == bean) {
                    // 1、如果没有spring的aop,这里bean和创建完成的object应该是一个
                    // 2、如果有aop,也是一样(AbstractAutoProxyCreator中判断了如果对三级缓存中的对象进行了增强代理,在初始化之后就不会再次代理)
					exposedObject = earlySingletonReference;
				}
                // 如果不一样,那说明对象有其他的代理途径,导致最后创建完成的对象和提前暴露的对象不一致了
                // 这种情况如果提前暴露的对象已经被注入到其他对象,进行报错(有个allowRawInjectionDespiteWrapping开关控制)
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException();
					}
				}
			}
		}

		return exposedObject;
	}

来看三级缓存的getEarlyBeanReference

如果需要代理则通过SmartInstantiationAwareBeanPostProcessor实现类来进行bean的代理,否则直接返回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;
					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
				}
			}
		}
		return exposedObject;
	}

实现类:AbstractAutoProxyCreator#getEarlyBeanReference,正是一般情况下初始化单例bean后进行aop代理的类,代码如下,调用的代理核心方法是一致的。earlyProxyReferences这个map保证了对提前暴露的对象代理之后,初始化阶段就不再代理了

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
		implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {

    // 对提前暴露的bean对象的代理操作
	@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初始化最后的代理操作
	@Override
	public Object postProcessAfterInitialization(@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;
	}
}

有了这个三级缓存之后,在循环依赖发生后,在本文最开始的代码doGetBean方法开头的getSingleton(beanName)中就会从三级缓存中查询到这个proxy对象,然后将其作为半成品放到二级缓存中

	public Object getSingleton(String beanName) {
		return getSingleton(beanName, true);
	}

	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 一级缓存查找
        Object singletonObject = this.singletonObjects.get(beanName);
        
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
                // 二级
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
                    // 三级
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
                        // 三级如果有,调用getObject获取到提前暴露的对象后,转移到二级缓存
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

----------------------------------------------

我看了spring2.5这块的代码,2.5的时候只有一级缓存,是直接将半成品放到一级缓存中,跟现在还不太一样,也没有支持aop代理的情况。

我猜之所以改成现在这样的三级缓存,一是将半成品和完成品分开,二是因为如果仅仅二级缓存要支持AOP的话,那势必要改目前创建bean的主流程,在实例化后就进行代理,改动太大,所以增加了三级缓存提供了一个提前代理的口子专门解决循环依赖,主流程不变

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值