spring解决循环依赖-三级缓存:源码解析

  • 前言

        源码分析spring创建单例bean循环依赖怎么解决? 循环依赖和aop同时发生时怎么解决的?为什么使用三级缓存?

一.什么是spring循环依赖

@Component
public class AService {
    @Autowired
    private BService bService;


    @Transactional
    public void test() {
        bService.test();
    }
}


@Component
public class BService {
    @Autowired
    private AService aService;

    public void test() {
        aService.test();
    }
}

        可以看到AService和BService互相是对方的属性,假如AService先创建,那么创建AService时会注入属性BService,这时spring容器又会去创建BService,创建BService时又会注入属性AService这时又会去创建AService,就形成了循环依赖。另外自引用(AService注入AService),间接引用(A->B->C-A)也是循环依赖.

        同时注入的属性可能是代理类比如BService注入的AService需要事务代理(test方法有事务注解@Transactional),那在创建AService的哪个阶段会创建代理类呢?

        bean的生命周期包括实例化,属性注入,初始化,销毁,只有初始化完成的bean才能被正常使用。

        spring只解决了单例bean的循环依赖问题,没有解决原型bean的循环依赖问题,它的主要思想就是把没有初始化完成的bean放入一个map集合中,属性注入就是一个对象地址引用,对象实例化后会分配内存地址,发生循环依赖时就可以从map中获取提前暴露的bean,从而打破循环依赖条件最后所有的bean都能初始化完成。而原型bean在循环依赖时每次创建都是新的对象,所以无法通过提前暴露的方式解决,以下分析过程都是按生成单例bean为前提。

        下面通过源码分析循环依赖的解决过程

2.spring容器刷新过程

     单例bean的创建发生在AbstractApplicationContext的refresh方法中

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// 刷新前准备设置其启动日期和活动标志等。
			prepareRefresh();

			// 创建BeanFactory
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 配置工厂的标准上下文特征,例如上下文的 ClassLoader 和后处理器
			prepareBeanFactory(beanFactory);

			try {
				// 允许在某些ApplicationContext实现中注册特殊的BeanPostProcessor等
				postProcessBeanFactory(beanFactory);

				// 调用BeanFactoryPostProcessor如ConfigurationClassPostProcessor扫描所有的bean
				invokeBeanFactoryPostProcessors(beanFactory);

				// 注册后置处理器BeanPostProcessor
				registerBeanPostProcessors(beanFactory);

				// 初始化 MessageSource
				initMessageSource();

				// 初始化事件广播
				initApplicationEventMulticaster();

				// 重写该方法以添加特定于上下文的刷新工作,如 springboot中
                //AnnotationConfigServletWebServerApplicationContext嵌入tomcat
				onRefresh();

				// 注册事件监听ApplicationListener
				registerListeners();

				// 遍历所有已经注册的BeanDefinition创建bean
				finishBeanFactoryInitialization(beanFactory);

				// 完成此上下文的刷新,调用 LifecycleProcessor 的 onRefresh() 方法并发布 
                //ContextRefreshedEvent事件等
				finishRefresh();
			}

循环依赖发生在bean创建过程,finishBeanFactoryInitialization(beanFactory)就是创建bean的
 

.单例bean的创建过程

finishBeanFactoryInitialization内部最终调用org.springframework.beans.factory.BeanFactory#getBean(java.lang.String)方法

BeanFactory默认实现DefaultListableBeanFactory,看下通过beanName创建bean的方法

getBean(beanName)

@Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}

具体的创建过程是getBean(beanName),getBean会调用doGetBean:

doGetBean

//只保留关键源码
protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {

		String beanName = transformedBeanName(name);
		Object bean;

		// 从缓存中获取
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
	        //当前bean是FactoryBean,那么要从FactoryBean获取最终bean,可先忽略
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}else{
            if (mbd.isSingleton()) {
                    //创建单例bean,核心的创建逻辑在createBean方法中
					sharedInstance = getSingleton(beanName, () -> {
						try {
                             //创建bean的核心逻辑        
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							destroySingleton(beanName);
							throw ex;
						}
					});
                    //当前bean是FactoryBean,那么要从FactoryBean获取最终bean,可先忽略
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
        }
return (T) bean;

doGetBean的逻辑很清晰:

        1.先从缓存获取bean,获取到则返回

           getSingleton(beanName):

public Object getSingleton(String beanName) {
		return getSingleton(beanName, true);
	}
最终调用getSingleton(String beanName, boolean allowEarlyReference):
//一级缓存singletonObjects存放已经创建完毕的bean
//二级缓存earlySingletonObjects存在已经实例化,还没有属性注入和初始化完成的bean
//三级缓存singletonFactories存放的是创建bean的工厂

//三级缓存就是三个map
//private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
//private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		//先从一级缓存获取
        Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            //一级缓存获取不到并且当前bean正在创建则从二级缓存获取
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
                   //二级缓存获取不到并且支持获取早期的bean则从三级缓存获取
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
                        //从三级缓存获取工厂并创建bean,把创建的bean放入二级缓存并删除三级缓存
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

        2 .获取不到就创建bean

             getSingleton(String beanName, ObjectFactory<?> singletonFactory)

        下面的流程以先创建AService为前提,此时缓存中AService不存在,那么就会创建AService

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
            //从一级缓存获取,此时刚开始创建肯定获取不到
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
                //当前正在销毁bean则报异常
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
                //添加beanName到Set集合中记录当前bean正在创建:this.singletonsCurrentlyInCreation.add(beanName)
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
                    //创建bean:调用createBean方法
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					// Has the singleton object implicitly appeared in the meantime ->
					// if yes, proceed with it since the exception indicates that state.
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throw ex;
					}
				}
				catch (BeanCreationException ex) {
					if (recordSuppressedExceptions) {
						for (Exception suppressedException : this.suppressedExceptions) {
							ex.addRelatedCause(suppressedException);
						}
					}
					throw ex;
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
                    //清除当前bean正在创建记录: 
                    //this.singletonsCurrentlyInCreation.remove(beanName)
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
                    //把bean放入一级缓存,并清除二,三级缓存
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

getSingleton(String beanName, ObjectFactory<?> singletonFactory)主要步骤:

        2.1.从一级缓存获取bean,获取到则返回,否则往下执行
        2.2.将beanName添加到singletonsCurrentlyInCreation表示当前bean正在创建
protected void beforeSingletonCreation(String beanName) {
        //inCreationCheckExclusions保存的都是不需要检查的bean
        //singletonsCurrentlyInCreation保存的都是当前正在创建的bean
        
        //当前bean需要检查时,就添加singletonsCurrentlyInCreation
		if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
            //当添加不成功时,说明当前bean正在创建现在又要创建,也就时发生了循环依赖才会这样
            //这里发生循环依赖是直接报错的,实际上第一次创建时进行了缓存(三级缓存),发生循环依赖再次创建是直接取缓存的,不会走这里
			throw new BeanCurrentlyInCreationException(beanName);
		}
	}

//当spring没有解决循环依赖时就会报这个错
public BeanCurrentlyInCreationException(String beanName) {
		super(beanName,
				"Requested bean is currently in creation: Is there an unresolvable circular reference?");
	}
        2.3.createBean

调用singletonFactory.getObject()创建bean,也就是createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)方法

        createBean:           

//只保留主要源码
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {


    RootBeanDefinition mbdToUse = mbd;
    try {
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
}

         最终调用doCreateBean(beanName, mbdToUse, args)

     doCreateBean:创建bean的核心逻辑,也就是bean的生命周期逻辑,能走到这里说明bean是第一次被创建,换句话说每个bean只会经历一次这个方法

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {
        
        //实例化:通过反射实例化bean
        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;
		}
        
        //当前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");
			}
            //加入三级缓存:解决循环依赖和AOP同时发生情况的精妙之处
            //这里只是允许循环依赖的发生但并不一定真正发生循环依赖,并且bean第一次创建并不知道后 
            //面会不会发生循环依赖,妙处就是它是一个函数,此处并不会真正执行,等待被调用就行了
            //三级缓存只有循环依赖真正发生时才会被调用也就是执行getEarlyBeanReference方法,内 
            //部调用aop生成代理类
            //什么时候被调用的呢?接着往下看
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

        Object exposedObject = bean;
		try {
            //属性注入:此处AService注入属性BService,会套娃执行getBean(beanName)创建BService
			populateBean(beanName, mbd, instanceWrapper);
            //初始化:1.执行初始化方法 
            //2.后置处理器方法:aop就是通过后置处理器完成的
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}

        //重新获取bean,重新获取的bean可能是原始bean也可能是代理bean,具体情况后续说明
        if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				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(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

}

doCreateBean的过程:

                2.3.1 实例化bean
                2.3.2 添加当前bean的三级缓存

                 当前bean是单例,并且正在创建中,并且容器支持循环依赖时earlySingletonExposure=true,并且添加当前bean的三级缓存。

                 addSingletonFactory:

                  

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(singletonFactory, "Singleton factory must not be null");
		synchronized (this.singletonObjects) {
			if (!this.singletonObjects.containsKey(beanName)) {
                //添加三级缓存
				this.singletonFactories.put(beanName, singletonFactory);
                //删除二级缓存
				this.earlySingletonObjects.remove(beanName);
				this.registeredSingletons.add(beanName);
			}
		}
	}

                 getEarlyBeanReference方法:                               

//执行spring的扩展接口SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference方法
//aop的基础类AbstractAutoProxyCreator就实现了该扩展接口,它的作用就是通过动态代理生成当前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的实现
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
	Object cacheKey = getCacheKey(bean.getClass(), beanName);
	this.earlyProxyReferences.put(cacheKey, bean);
    //如果需要生成代理则返回代理bean,否则返回原始bean
	return wrapIfNecessary(bean, beanName, cacheKey);
}

        三级缓存本身是一个函数,只有调用的时候才会执行,这一步只是创建函数并没有执行,什么时执行的呢?接着往下

        2.3.3.属性注入

                循环依赖就是发生在此阶段,此时AService注入BService就会执行getBean(beanName)创建BService和创建AService一样的流程,至此bean的创建流程大概为:

                创建AService --->添加三级缓存 --->注入BService --->创建BService ---> 添加三级缓存 ---> 注入AService --->创建AService

                此时发生循环依赖再次创建AService,先从缓存获取AService的实例,因为AService的三级缓存在第一次创建AService的步骤2.3.2已经存入,再次创建就会通过三级缓存获取bean也就是调用函数getEarlyBeanReference获取AService,这样BService的属性注入完成,最终AService注入BService完成属性注入

                 在第一次创建AService时其实并不知道会发生循环依赖,只有属性注入阶段才会发现,当然循环依赖也不会一定发生,三级缓存只在发生循环依赖时才会被执行。

        2.3.4.初始化

                看下initializeBean初始化的过程:

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
       //执行后置处理器BeanPostProcessor的postProcessBeforeInitialization
       //其中就包含执行@PostConstruct初始化方法的处理器CommonAnnotationBeanPostProcessor
       Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}
        
       //执行初始化方法InitializingBean的afterPropertiesSet方法
       try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		} 

        //执行后置处理器BeanPostProcessor的postProcessAfterInitialization方法
        //也是aop生成代理类的地方,AbstractAutoProxyCreator的postProcessAfterInitialization方法
        if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}
        
        
return wrappedBean;
}
        2.3.5.重新获取bean

                这里会有几种情况:

                        1.earlySingletonExposure=true,允许循环依赖并且确实发生了循环依赖                                                    调用getSingleton(beanName, false)具体查看步骤1调用getSingleton(String                                    beanName, boolean allowEarlyReference),因为循环依赖已经发生,也就                                      是 AService的三级缓存已经执行(获取的bean会放入二级缓存),那么此                                      时取到的就是二级缓存的bean(原始bean或代理bean具体看bean本身是否                                    需要代理)     

                         2.earlySingletonExposure=true,允许循环依赖但没有发生循环依赖     

                                调用getSingleton(beanName, false)具体查看步骤1调用getSingleton(String                                    beanName, boolean allowEarlyReference),因为循环依赖没发生,此时二级                                  缓存是空的,那么返回的就是正常流程初始化完成的exposedObject,具体看                                   2.3.4中applyBeanPostProcessorsAfterInitialization调用后置处理器的方法,                                   返回的是原始bean或代理bean(具体看bean本身是否需要代理)

                          3.earlySingletonExposure=false,不支持循环依赖

                                 那么返回的就是正常流程初始化完成的exposedObject,具体看 2.3.4中                                           applyBeanPostProcessorsAfterInitialization调用后置处理器的方法,                                               返回的是原始bean或代理bean(具体看bean本身是否需要代理)

                 生成aop的地方有个问题,循环依赖和aop同时发生时,创建AService的过程中属性注入和初始化都会生成代理类,那不是重复生成代理类了?

                  再看下AbstractAutoProxyCreator的postProcessAfterInitialization方法 和getEarlyBeanReference方法

//AbstractAutoProxyCreator的getEarlyBeanReference方法
public Object getEarlyBeanReference(Object bean, String beanName) {
        //key:就是beanName 或(如果是FactoryBean就是&加beanName)
		Object cacheKey = getCacheKey(bean.getClass(), beanName);
        //发生循环依赖通过三级缓存执行该方法
		this.earlyProxyReferences.put(cacheKey, bean);
		return wrapIfNecessary(bean, beanName, cacheKey);
}



//AbstractAutoProxyCreator的postProcessAfterInitialization方法
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;
	}

其实aop就发生在两个地方最终都是通过AbstractAutoProxyCreator生成的:

        1.发生循环依赖时,在属性注入阶段通过调用三级缓存来触发aop(调用getEarlyBeanReference)

        2. 在初始化完成后通过调用后置处理器触发aop(调用postProcessAfterInitialization)

属性注入在初始化之前,所以对于同一个bean,getEarlyBeanReference是优先于postProcessAfterInitialization执行的,所以通过   earlyProxyReferences缓存来判断避免了重复生成代理类,二者只会有一处真正进行aop

        2.4.移除当前bean正在创建的标记

                  从singletonsCurrentlyInCreation中移除当前beanName

        2.5.将单例bean放入缓存
protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
            //放入一级缓存,说明此时创建的bean是初始化完成的bean,可以正常使用了
			this.singletonObjects.put(beanName, singletonObject);
            //删除三级缓存,什么时候存进去的接着往下看createBean
			this.singletonFactories.remove(beanName);
            //删除二级缓存,什么时候存进去的接着往下看createBean
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}

至此bean就创建完毕了 

三.总结

        现在总结下为什么使用三级缓存解决循环依赖

        其实解决循环依赖只用二级缓存就能解决,根本思路就是把未初始化完成的bean放入二级缓存earlySingletonObjects提前暴露,甚至不考虑安全性单单从解决循环依赖的角度出发,只使用一级缓存singletonObjects就能解决,不过未初始化完成的bean被使用有可能造成安全问题。

        那为什么使用三级缓存呢?假设现在只有两级缓存,那么就需要在属性注入前就要生成代理类,也就是在AService实例化阶段就生成代理类放入二级缓存earlySingletonObjects,这样确实也能解决循环依赖的问题。但是当循环依赖和aop同时发生时,但是这就破坏了bean的生命周期(而且在没有发生循环依赖时没必要这么做),正常aop发生在初始化之后,但是现在提前到了实例化阶段,实例化阶段还要处理生成代理类的逻辑,这样生命周期的过程就耦合了。使用三级缓存通过函数的形式使aop延迟要属性注入阶段,同时尽最大程度保持生命周期每一步逻辑的解耦。

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值