spring源码bean生命周期篇 五 如何解决循环依赖

spring源码bean生命周期篇 五 如何解决循环依赖 一.spring循环依赖1. 什么是循环依赖bean的生命周期前面的章节我们有讲解过大量的源码我们粗略的分为这几步spring扫描class获取BeanDefintionspring根据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容器名称为earlySigthonObjects1. bean a 实例化后放入存放早期bean的容器earlySigthonObjects中2. 创建bean a 的过程中需要填充属性b存放完整bean两个容器中都没有 bean b触发创建 bean b3. bean b 实例化 放入早期bean容器earlySigthonObjects中并且填充属性a拿出1步骤存放earlySigthonObjects的早期bean abean b顺利被创建4. bean a 即可创建完成以创建bean B为例,如下图所示3. Spring Aop怎么解决循环依赖在讲这个课题之前我们回忆一下bean周期在创建bean之前首先要找到对应的类并且加载实例化前执行 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation方法实例化实例化后执行InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation方法为属性赋值执行InstantiationAwareBeanPostProcessor.postProcessPropertiesInstantiationAwareBeanPostProcessor.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.getEarlyBeanReferenceprotectedObjectgetEarlyBeanReference(StringbeanName,RootBeanDefinitionmbd,Objectbean){ObjectexposedObjectbean;if(!mbd.isSynthetic()hasInstantiationAwareBeanPostProcessors()){for(BeanPostProcessorbp:getBeanPostProcessors()){if(bpinstanceofSmartInstantiationAwareBeanPostProcessor){SmartInstantiationAwareBeanPostProcessoribp(SmartInstantiationAwareBeanPostProcessor)bp;exposedObjectibp.getEarlyBeanReference(exposedObject,beanName);}}}returnexposedObject;}org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.getEarlyBeanReferenceOverridepublicObjectgetEarlyBeanReference(Objectbean,StringbeanName){ObjectcacheKeygetCacheKey(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[]specificInterceptorsgetAdvicesAndAdvisorsForBean(bean.getClass(),beanName,null);if(specificInterceptors!DO_NOT_PROXY){this.advisedBeans.put(cacheKey,Boolean.TRUE);//创建代理对象ObjectproxycreateProxy(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的代理对象ObjectcacheKeygetCacheKey(bean.getClass(),beanName);if(this.earlyProxyReferences.remove(cacheKey)!bean){returnwrapIfNecessary(bean,beanName,cacheKey);}}returnbean;}二.spring循环依赖源码详细解析singletonObjects缓存经过了完整生命周期的beanearlySingletonObjects缓存未经过完整生命周期的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 b4.调用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.AbstractBeanFactoryTTgetBean(Stringname){ObjectbeangetSingleton(beanName);if(beannull){//alreadyCreated.add(beanName) alreadyCreated存储的已经被创建过一次的beanNamemarkBeanAsCreated(beanName);//获取bean定义finalRootBeanDefinitionmbdgetMergedLocalBeanDefinition(beanName);if(mbd.isSingleton()){//创建bean入参 String beanNameObjectFactory factorysharedInstancegetSingleton(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 were 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一级缓存中获取beanObjectsingletonObjectthis.singletonObjects.get(beanName);//以及缓存为空从第二级缓存中获取beanif(singletonObjectnullisSingletonCurrentlyInCreation(beanName)){synchronized(this.singletonObjects){singletonObjectthis.earlySingletonObjects.get(beanName);//二级缓存为null如果allowEarlyReference为true从三级缓存拿出singletonFactory并执行Object方法其返回结果放入二级缓存并从三级缓存去掉if(singletonObjectnullallowEarlyReference){ObjectFactory?singletonFactorythis.singletonFactories.get(beanName);if(singletonFactory!null){singletonObjectsingletonFactory.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){ObjectsingletonObjectthis.singletonObjects.get(beanName);if(singletonObjectnull){//singletonsCurrentlyInCreation.add(beanName)beforeSingletonCreation(beanName);booleannewSingletonfalse;try{//结合上面的代码。实际上调用的是createBean(beanName, mbd, args)singletonObjectsingletonFactory.getObject();newSingletontrue;}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.doCreateBeanprotectedObjectdoCreateBean(StringbeanName,RootBeanDefinitionmbd,NullableObject[]args)throwsBeanCreationException{BeanWrapperinstanceWrappernull;if(instanceWrappernull){instanceWrappercreateBeanInstance(beanName,mbd,args);finalObjectbeaninstanceWrapper.getWrappedInstance();Class?beanTypeinstanceWrapper.getWrappedClass();applyMergedBeanDefinitionPostProcessors(mbd,beanType,beanName);//isSingletonCurrentlyInCreationsingletonsCurrentlyInCreation.contains(beanName)booleanearlySingletonExposure(mbd.isSingleton()this.allowCircularReferencesisSingletonCurrentlyInCreation(beanName));if(earlySingletonExposure){//放入第三级缓存addSingletonFactory(beanName,()-getEarlyBeanReference(beanName,mbd,bean));}ObjectexposedObjectbean;//填充bean的属性populateBean(beanName,mbd,instanceWrapper);//初始化beanexposedObjectinitializeBean(beanName,exposedObject,mbd);if(earlySingletonExposure){//从第二级缓存中获取当前beanObjectearlySingletonReferencegetSingleton(beanName,false);if(earlySingletonReference!null){if(exposedObjectbean){exposedObjectearlySingletonReference;}elseif(!this.allowRawInjectionDespiteWrappinghasDependentBean(beanName)){//this.dependentBeanMap.get(beanName)在bean是初始化后进行属性填充之后会注册依赖和被依赖的关系往dependentBeanMap新增依赖关系//以Demo 创建Bean A 为例beanName为a需要注入的属性值为bean b所以获取到的dependentBeans为bString[]dependentBeansgetDependentBeans(beanName);SetStringactualDependentBeansnewLinkedHashSet(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){AanewA();BeanUtils.copyProperties(bean,A);returna;}returnbean;}}先创建bean a先创建bean b以当前demo来说先创建bean a会抛出BeanCurrentlyInCreationException而先创建bean b却不会所以可能会出现开发环境不同bean 的创建顺序不同导致有的同事可以正常启动项目而有的会抛出BeanCurrentlyInCreationException终止项目运行。解决方法加上lazy注解具体可查阅lazy注解有关资料这里就不讲述了