spring源码bean生命周期篇 五 如何解决循环依赖
一.spring循环依赖
1. 什么是循环依赖?
bean的生命周期前面的章节我们有讲解过大量的源码,我们粗略的分为这几步
- spring扫描class获取BeanDefintion
- spring根据BeanDefintion实例化bean
- 创建bean之前需要实例化对象,实例化后填充原始对象中的属性(依赖注入)
@ServicepublicclassB{@AutowiredpublicAa;}@ServicepublicclassA{@AutowiredprivateBb;}如下图所示:
以先创建bean a为例,实例化后填充属性b时,发现bean b还没被创建不在单例池(singletonObjects)中,这时侯会去创建bean b,在实例化对象之后,需要填充属性a,这时候发现spring 的单例池(singletonObjects) 中也没有bean a,又需要创建bean A;
创建bean a 需要创建 bean b ,创建bean a 需要创建 bean b,不管先创建bean a 还是先创建bean b这样造成了死循环, 如果不处理的话,两个bean都无法创建,这时侯我们该如何打破僵局呢?
singletonObjects:中缓存的是已经经历了完整生命周期的bean对象
2. 如何打破循环依赖的僵局
在多数情况下,在实例化得到的对象,和最终的bean是同一个对象,只是实例化的对象没有进行属性填充以及初始化等步骤。因此我们可以提前暴露bean的方式解决
我们可以缓存实例化的得到的对象,这样的步骤就如下图所示,在spring源码中,缓存早期bean容器名称为earlySigthonObjects
1. bean a 实例化后放入存放早期bean的容器earlySigthonObjects中
2. 创建bean a 的过程中需要填充属性b,存放完整bean两个容器中都没有 bean b,触发创建 bean b
3. bean b 实例化 放入早期bean容器earlySigthonObjects中,并且填充属性a,拿出1步骤存放earlySigthonObjects的早期bean a,bean b顺利被创建
4. bean a 即可创建完成
以创建bean B为例,如下图所示:
3. Spring Aop怎么解决循环依赖
在讲这个课题之前,我们回忆一下bean周期
在创建bean之前,首先要找到对应的类并且加载
实例化前(执行 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation方法)
实例化
实例化后(执行InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation方法)
为属性赋值(执行InstantiationAwareBeanPostProcessor.postProcessProperties,InstantiationAwareBeanPostProcessor.postProcessPropertyValue后得到返回后进行applyPropertyValue方法如上图所示)
执行Aware接口的对应方法(invokeAwareMethods)
初始化前(执行BeanPostProcessor.postProcessBeforeInitialization方法)
- 初始化( 执行初始化方法)
初始化后(执行BeanPostProcessor.postProcessAfterInitialization方法)
在初始化过程中:
BeanPostProcessor.postProcessAfterInitialization方法和BeanPostProcessor.postProcessBeforeInitialization中对bean可以进行处理返回新的bean代替原来的bean
而AOP就是通过一个BeanPostProcessor来实现的,这个BeanPostProcessor就是
AnnotationAwareAspectJAutoProxyCreator,它的父类是AbstractAutoProxyCreator,而在设置了切面,那么这个类最终就需要生成一个代理对象,在之前的章节我们也有讲过这个类。
基于上面的场景想一个问题:
如下如果A的原始对象注入给B的属性之后,A的原始对象进行了AOP产生了一个代理对象 此时就会出现,对于A而言,它的Bean对象其实应该是AOP之后的代理对象,但实际上注入的是AOP代理之前的原始bean。
如下图所示:
但是AOP可以说是Spring中除开IOC的另外一大功能,而循环依赖又是属于IOC范畴的,所以这两大功 能想要并存,Spring需要特殊处理,为了解决Spring Aop的循环依赖,我们可以提前暴露AOP之后的代理对象来解决
解决方案:
引入singletonFactories(第三级缓存)把AOP的步骤提前:
singletonFactories中存的是某个beanName对应的ObjectFactory,在bean的生命周期中,
生成完原始对象之后,就会构造一个ObjectFactory存入singletonFactories中。这个ObjectFactory
是一个函数式接口,所以支持Lambda表达式:() -> getEarlyBeanReference(beanName, mbd,
bean)
getEarlyBeanReference对应的逻辑:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getEarlyBeanReference
protectedObjectgetEarlyBeanReference(StringbeanName,RootBeanDefinitionmbd,Objectbean){ObjectexposedObject=bean;if(!mbd.isSynthetic()&&hasInstantiationAwareBeanPostProcessors()){for(BeanPostProcessorbp:getBeanPostProcessors()){if(bpinstanceofSmartInstantiationAwareBeanPostProcessor){SmartInstantiationAwareBeanPostProcessoribp=(SmartInstantiationAwareBeanPostProcessor)bp;exposedObject=ibp.getEarlyBeanReference(exposedObject,beanName);}}}returnexposedObject;}org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.getEarlyBeanReference
@OverridepublicObjectgetEarlyBeanReference(Objectbean,StringbeanName){ObjectcacheKey=getCacheKey(bean.getClass(),beanName);//当前bean放入earlyProxyReferences代表已经进行了AOPthis.earlyProxyReferences.put(cacheKey,bean);returnwrapIfNecessary(bean,beanName,cacheKey);}protectedObjectwrapIfNecessary(Objectbean,StringbeanName,ObjectcacheKey){if(StringUtils.hasLength(beanName)&&this.targetSourcedBeans.contains(beanName)){returnbean;}//缓存是不需要AOP的对象,直接返回if(Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))){returnbean;}if(isInfrastructureClass(bean.getClass())||shouldSkip(bean.getClass(),beanName)){this.advisedBeans.put(cacheKey,Boolean.FALSE);returnbean;}// 获取所有可以应用到当前bean的切面逻辑Object[]specificInterceptors=getAdvicesAndAdvisorsForBean(bean.getClass(),beanName,null);if(specificInterceptors!=DO_NOT_PROXY){this.advisedBeans.put(cacheKey,Boolean.TRUE);//创建代理对象Objectproxy=createProxy(bean.getClass(),beanName,specificInterceptors,newSingletonTargetSource(bean));this.proxyTypes.put(cacheKey,proxy.getClass());returnproxy;}this.advisedBeans.put(cacheKey,Boolean.FALSE);returnbean;}publicObjectpostProcessAfterInitialization(@NullableObjectbean,StringbeanName){if(bean!=null){//进行AOP的不需要再次创建bean的代理对象ObjectcacheKey=getCacheKey(bean.getClass(),beanName);if(this.earlyProxyReferences.remove(cacheKey)!=bean){returnwrapIfNecessary(bean,beanName,cacheKey);}}returnbean;}二.spring循环依赖源码详细解析
- singletonObjects:缓存经过了完整生命周期的bean
- earlySingletonObjects:
缓存未经过完整生命周期的bean,如果某个bean出现了循环依赖,
就会提前把这个暂时未经过完整生命周期的bean放入earlySingletonObjects中,这个bean如果
要经过AOP,那么就会把代理对象放入earlySingletonObjects中,否则就是把原始对象放入
earlySingletonObjects,但是不管怎么样,就是是代理对象,代理对象所代理的原始对象也是
没有经过完整生命周期的,所以放入earlySingletonObjects我们就可以统一认为是未经过完整
生命周期的bean。 - singletonFactories:
缓存的是一个ObjectFactory,也就是一个Lambda表达式。在每个Bean 的生成过程中,经过实例化得到一个原始对象后,都会提前基于原始对象暴露一个Lambda表达 式,并保存到三级缓存中,这个Lambda表达式可能用到,也可能用不到,如果当前Bean没有出 现循环依赖,那么这个Lambda表达式没用,当前bean按照自己的生命周期正常执行,执行完后 直接把当前bean放入singletonObjects中,如果当前bean在依赖注入时发现出现了循环依赖 (当前正在创建的bean被其他bean依赖了),则从三级缓存中拿到Lambda表达式,并执行 Lambda表达式得到一个对象,并把得到的对象放入二级缓存((如果当前Bean需要AOP,那么 执行lambda表达式,得到就是对应的代理对象,如果无需AOP,则直接得到一个原始对象))。
4. 其实还要一个缓存,就是earlyProxyReferences,它用来记录某个原始对象是否进行过AOP 了下图是先解决bean a 和bean b循环依赖的证据 ,先创建a的流程如图所示
getBean(String name)
getBean调用了两个getSingleton方法
入参数只有一个beanName,当前方法是去看看spring容器中有没有当前名为beanName的bean,如果没有要判断当前bean是否在标记正在创建,如果标记为创建才会去找二级缓存,alowEarlyReference参数默认为true并二级缓存为null,才会找三级缓存获取早期bean
入参有两个参数,一个为beanName,一个为ObjectFactory,主要是创建bean,并把当前bean标记为正在创建
处理bean A和Bean B循环依赖的流程,以先创建Bean A为例
整个逻辑都在getBean(a)方法中
1. 调用getSingleton(a)从一二三级缓存中找bean A,这时候肯定是没有的,调用第二个getSingleton方法创建bean A,并标记bean A正在创建
2.创建bean A的过程中需要实例化A对象,并根据实例化的对象生成ObjectFactory,放入第三缓存
3.创建bean A的过程中需要填充属性b ,触发调用方法getBean(b)获取bean b
4.调用getSingleton(b),一二三级缓存中找bean A,这时候肯定是没有的,这时候调用第二个getSingleton方法创建Bean B,并标记bean B正在创建
5.创建bean B的过程中需要实例化B对象,并根据实例化的对象生成ObjectFactory,放入第三缓存
6.创建bean B的过程中需要填充属性a,这个时候会调用getBean(a)方法,但是与第一步不同的是第三缓存中可获得早期的bean A对象给属性a赋值
7.创建bean B成功后给bean A 的属性b赋值,bean A也可以创建成功
org.springframework.beans.factory.support.AbstractBeanFactory<T>TgetBean(Stringname){Objectbean=getSingleton(beanName);if(bean==null){//alreadyCreated.add(beanName) alreadyCreated存储的已经被创建过一次的beanNamemarkBeanAsCreated(beanName);//获取bean定义finalRootBeanDefinitionmbd=getMergedLocalBeanDefinition(beanName);if(mbd.isSingleton()){//创建bean,入参 String beanName,ObjectFactory factorysharedInstance=getSingleton(beanName,()->{returncreateBean(beanName,mbd,args);}}}protectedvoidmarkBeanAsCreated(StringbeanName){if(!this.alreadyCreated.contains(beanName)){synchronized(this.mergedBeanDefinitions){if(!this.alreadyCreated.contains(beanName)){// Let the bean definition get re-merged now that we're actually creating// the bean... just in case some of its metadata changed in the meantime.clearMergedBeanDefinition(beanName);this.alreadyCreated.add(beanName);}}}}getSingleton(String name)
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(beanName)
代码经过简化
publicObjectgetSingleton(StringbeanName){returngetSingleton(beanName,true);}protectedObjectgetSingleton(StringbeanName,booleanallowEarlyReference){//从spring一级缓存中获取beanObjectsingletonObject=this.singletonObjects.get(beanName);//以及缓存为空,从第二级缓存中获取beanif(singletonObject==null&&isSingletonCurrentlyInCreation(beanName)){synchronized(this.singletonObjects){singletonObject=this.earlySingletonObjects.get(beanName);//二级缓存为null,如果allowEarlyReference为true,从三级缓存拿出singletonFactory,并执行Object方法,其返回结果放入二级缓存,并从三级缓存去掉if(singletonObject==null&&allowEarlyReference){ObjectFactory<?>singletonFactory=this.singletonFactories.get(beanName);if(singletonFactory!=null){singletonObject=singletonFactory.getObject();this.earlySingletonObjects.put(beanName,singletonObject);this.singletonFactories.remove(beanName);}}}}returnsingletonObject;}getSingleton(String name, ObjectFactory<?> singletonFactory)
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(beanName,ObjectFactory)
代码经过简化
publicObjectgetSingleton(StringbeanName,ObjectFactory<?>singletonFactory){synchronized(this.singletonObjects){ObjectsingletonObject=this.singletonObjects.get(beanName);if(singletonObject==null){//singletonsCurrentlyInCreation.add(beanName)beforeSingletonCreation(beanName);booleannewSingleton=false;try{//结合上面的代码。实际上调用的是createBean(beanName, mbd, args)singletonObject=singletonFactory.getObject();newSingleton=true;}finally{//singletonsCurrentlyInCreation.remove(beanName)afterSingletonCreation(beanName);}if(newSingleton){//singletonObjects.put(beanName, singletonObject);addSingleton(beanName,singletonObject);}}returnsingletonObject;}}protectedvoidaddSingleton(StringbeanName,ObjectsingletonObject){synchronized(this.singletonObjects){this.singletonObjects.put(beanName,singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}接下来调用create方法org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean
protectedObjectdoCreateBean(StringbeanName,RootBeanDefinitionmbd,@NullableObject[]args)throwsBeanCreationException{BeanWrapperinstanceWrapper=null;if(instanceWrapper==null){instanceWrapper=createBeanInstance(beanName,mbd,args);finalObjectbean=instanceWrapper.getWrappedInstance();Class<?>beanType=instanceWrapper.getWrappedClass();applyMergedBeanDefinitionPostProcessors(mbd,beanType,beanName);//isSingletonCurrentlyInCreation=>singletonsCurrentlyInCreation.contains(beanName)booleanearlySingletonExposure=(mbd.isSingleton()&&this.allowCircularReferences&&isSingletonCurrentlyInCreation(beanName));if(earlySingletonExposure){//放入第三级缓存addSingletonFactory(beanName,()->getEarlyBeanReference(beanName,mbd,bean));}ObjectexposedObject=bean;//填充bean的属性populateBean(beanName,mbd,instanceWrapper);//初始化beanexposedObject=initializeBean(beanName,exposedObject,mbd);if(earlySingletonExposure){//从第二级缓存中获取当前bean,ObjectearlySingletonReference=getSingleton(beanName,false);if(earlySingletonReference!=null){if(exposedObject==bean){exposedObject=earlySingletonReference;}elseif(!this.allowRawInjectionDespiteWrapping&&hasDependentBean(beanName)){//this.dependentBeanMap.get(beanName),在bean是初始化后进行属性填充之后会注册依赖和被依赖的关系,往dependentBeanMap新增依赖关系//以Demo 创建Bean A 为例,beanName为a,需要注入的属性值为bean b,所以获取到的dependentBeans为bString[]dependentBeans=getDependentBeans(beanName);Set<String>actualDependentBeans=newLinkedHashSet<>(dependentBeans.length);for(StringdependentBean:dependentBeans){//并且bean b 至少触发创建过// bean b已经开始创建,那么bean b注入的早期的bean对象,而不是经过整个生命周期的bean对象if(!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)){actualDependentBeans.add(dependentBean);}}if(!actualDependentBeans.isEmpty()){thrownewBeanCurrentlyInCreationException(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 "+"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");}}}}}}}protectedbooleanremoveSingletonIfCreatedForTypeCheckOnly(StringbeanName){if(!this.alreadyCreated.contains(beanName)){removeSingleton(beanName);returntrue;}else{returnfalse;}三.spring循环依赖问题的再度解决
在初始化过程中:
BeanPostProcessor.postProcessAfterInitialization方法和BeanPostProcessor.postProcessBeforeInitialization中对bean可以进行处理返回新的bean代替原来的bean,上述我们只处理了AOP有关的基于BeanPostProcessor.postProcessAfterInitialization,并不代表所有的BeanPostProcessor.postProcessAfterInitialization的都没有循环依赖问题
这里我们先上demo,根据上述讲解的源码进行分析:
@ServicepublicclassA{@AutowiredprivateBb;}@ServicepublicclassB{@AutowiredpublicAa;}@ComponentpublicclassBeanPostProcessorDimplementsBeanPostProcessor{@OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName){if(beaninstanceofA){Aa=newA();BeanUtils.copyProperties(bean,A);returna;}returnbean;}}先创建bean a
先创建bean b
以当前demo来说,先创建bean a会抛出BeanCurrentlyInCreationException,而先创建bean b却不会,所以可能会出现开发环境不同,bean 的创建顺序不同导致有的同事可以正常启动项目,而有的会抛出BeanCurrentlyInCreationException终止项目运行。
解决方法加上@lazy注解,具体可查阅lazy注解有关资料,这里就不讲述了
