核心内容摘要
拍拍拍1000免费看剧的app
Spring 解决循环依赖主要通过三级缓存机制来实现。
什么是循环依赖循环依赖是指两个或多个 Bean 之间相互依赖形成闭环。
例如A 依赖 BB 依赖 A或者更复杂的情况A 依赖 BB 依赖 CC 依赖 A
Spring 的三级缓存机制Spring 使用三个 Map 来管理 Bean 的实例// 一级缓存存放完整的 Bean已实例化、已填充属性、已初始化privatefinalMapString,ObjectsingletonObjectsnewConcurrentHashMap(
;// 二级缓存存放早期暴露的 Bean已实例化、未填充属性privatefinalMapString,ObjectearlySingletonObjectsnewConcurrentHashMap(
;// 三级缓存存放 Bean 工厂用于生成早期 Bean 的代理对象privatefinalMapString,ObjectFactory?singletonFactoriesnewHashMap(
;
解决循环依赖的流程以 A、B 相互依赖为例
创建 A 的实例//
实例化 A调用构造函数AacreateBeanInstance(a);//
将 A 的工厂放入三级缓存addSingletonFactory(a,()-getEarlyBeanReference(a,a));
填充 A 的属性发现依赖 B//
尝试获取 BBbgetBean(b);
创建 B 的实例//
实例化 BBbcreateBeanInstance(b);//
将 B 的工厂放入三级缓存addSingletonFactory(b,()-getEarlyBeanReference(b,b));
填充 B 的属性发现依赖 A//
尝试获取 AAagetBean(a);//
从三级缓存获取 A 的工厂创建早期引用ObjectFactory?factorysingletonFactories.get(a);AearlyAfactory.getObject();//
将早期 A 从三级缓存移到二级缓存earlySingletonObjects.put(a,earlyA);singletonFactories.remove(a);
完成 B 的创建//
B 初始化完成放入一级缓存addSingleton(b,b);
完成 A 的创建//
A 获取到 B填充属性完成//
A 初始化完成放入一级缓存addSingleton(a,a);//
从二级缓存移除 AearlySingletonObjects.remove(a);
核心源码分析
getBean() 方法protectedTTdoGetBean(Stringname,ClassTrequiredType,...){//
尝试从缓存获取ObjectsharedInstancegetSingleton(beanName);if(sharedInstance!null){return(T)getObjectForBeanInstance(sharedInstance,name,beanName);}//
创建 Bean 实例returncreateBean(beanName,mbd,args);}
getSingleton() 方法关键protectedObjectgetSingleton(StringbeanName,booleanallowEarlyReference){//
从一级缓存获取ObjectsingletonObjectthis.singletonObjects.get(beanName);//
一级缓存没有且当前 Bean 正在创建中if(singletonObjectnullisSingletonCurrentlyInCreation(beanName)){//
从二级缓存获取singletonObjectthis.earlySingletonObjects.get(beanName);//
二级缓存没有且允许早期引用if(singletonObjectnullallowEarlyReference){synchronized(this.singletonObjects){//
双重检查singletonObjectthis.singletonObjects.get(beanName);if(singletonObjectnull){singletonObjectthis.earlySingletonObjects.get(beanName);if(singletonObjectnull){//
从三级缓存获取工厂ObjectFactory?singletonFactorythis.singletonFactories.get(beanName);if(singletonFactory!null){//
调用工厂方法获取早期 BeansingletonObjectsingletonFactory.getObject();//
放入二级缓存this.earlySingletonObjects.put(beanName,singletonObject);//
从三级缓存移除this.singletonFactories.remove(beanName);}}}}}}returnsingletonObject;}
createBean() 方法protectedObjectcreateBean(StringbeanName,RootBeanDefinitionmbd,Object[]args){//
实例化 BeanObjectbeanInstancedoCreateBean(beanName,mbdToUse,args);returnbeanInstance;}protectedObjectdoCreateBean(StringbeanName,RootBeanDefinitionmbd,Object[]args){//
实例化ObjectbeancreateBeanInstance(beanName,mbd,args);//
允许循环依赖将工厂放入三级缓存booleanearlySingletonExposure(mbd.isSingleton()this.allowCircularReferencesisSingletonCurrentlyInCreation(beanName));if(earlySingletonExposure){addSingletonFactory(beanName,()-getEarlyBeanReference(beanName,mbd,bean));}//
填充属性可能触发循环依赖populateBean(beanName,mbd,bean);//
初始化ObjectexposedObjectinitializeBean(beanName,exposedObject,mbd);//
放入一级缓存if(earlySingletonExposure){ObjectearlySingletonReferencegetSingleton(beanName,false);if(earlySingletonReference!null){exposedObjectearlySingletonReference;}}addSingleton(beanName,exposedObject);returnexposedObject;}
为什么需要三级缓存一级缓存不够吗一级缓存只存放完整的 Bean循环依赖时 Bean 还未创建完成二级缓存不够吗二级缓存可以解决简单循环依赖但当涉及 AOP 代理时需要三级缓存来延迟创建代理对象三级缓存的作用// 三级缓存存放的是工厂可以延迟创建代理对象addSingletonFactory(beanName,()-getEarlyBeanReference(beanName,mbd,bean));protectedObjectgetEarlyBeanReference(StringbeanName,RootBeanDefinitionmbd,Objectbean){ObjectexposedObjectbean;// 如果需要 AOP 代理在这里创建代理对象if(!mbd.isSynthetic()hasInstantiationAwareBeanPostProcessors()){for(BeanPostProcessorbp:getBeanPostProcessors()){if(bpinstanceofSmartInstantiationAwareBeanPostProcessor){SmartInstantiationAwareBeanPostProcessoribp(SmartInstantiationAwareBeanPostProcessor)bp;exposedObjectibp.getEarlyBeanReference(exposedObject,beanName);}}}returnexposedObject;}
循环依赖的限制
只能解决单例 Bean 的循环依赖// 原型 Bean 不支持循环依赖Scope(prototype)// 会抛出异常
构造器注入无法解决// 构造器注入会抛出 BeanCurrentlyInCreationExceptionComponentpublicclassA{privatefinalBb;publicA(Bb){// 构造器注入this.bb;}}
Async 注解的 Bean// Async 会导致循环依赖失败ComponentpublicclassA{Asyncpublicvoidmethod(){}}
解决方案
使用 Lazy 注解构造器注入ComponentpublicclassA{privatefinalBb;publicA(LazyBb){// 延迟加载this.bb;}}
改用 Setter 注入ComponentpublicclassA{privateBb;AutowiredpublicvoidsetB(Bb){this.bb;}}
使用 PostConstruct 初始化ComponentpublicclassA{AutowiredprivateBb;PostConstructpublicvoidinit(){// 在这里使用 b}}
重新设计避免循环依赖使用事件驱动引入中间层使用设计模式如观察者模式
八、
总结Spring 通过三级缓存机制巧妙地解决了单例 Bean 的循环依赖问题一级缓存存放完整的 Bean二级缓存存放早期暴露的 Bean已实例化但未填充属性三级缓存存放 Bean 工厂用于生成代理对象核心思想是提前暴露未完全初始化的 Bean 引用让其他 Bean 可以引用它从而打破循环依赖的僵局。
但要注意这种机制只适用于 Setter 注入的单例 Bean构造器注入和原型 Bean 的循环依赖需要通过其他方式解决。