纠纷奇闻作文社交美文家庭
聚热点
家庭城市
爱好生活
创业男女
能力餐饮
美文职业
心理周易
母婴奇趣
两性技能
社交传统
新闻范文
工作个人
思考社会
作文职场
家居中考
兴趣安全
解密魅力
奇闻笑话
写作笔记
阅读企业
饮食时事
纠纷案例
初中历史
说说童话
乐趣治疗

不要再问Spring是如何解决循环依赖了

1月21日 夜如影投稿
  1、什么是循环依赖?
  循环依赖主要来次三个方面,第一种A相互依赖,第二种是A依赖B,B依赖A,第三种是A依赖B,B依赖C,C依赖A。
  总结一句话就是对象之间形成环形依赖。
  代码如下:
  第一种:publicclassA{privateAa;}
  第二种:publicclassA{privateBb;}classB{privateAa;}
  第三种:publicclassA{privateBb;}classB{privateCc;}classC{privateAa;}2、Spring三级缓存是什么?第一级缓存:singletonObjects,用于缓存成品的bean,保证Spring的单例属性。第二级缓存:earlySingletonObjects,用于保存实例化完成的半成品bean实例,包括AOP代理对象。第三级缓存:singletonFactories,MapString,ObjectF?,Map的Value是一个对象的代理工厂,用来存放对象的代理工厂用于保存bean创建工厂,以便后面有机会创建代理对象。为打破循环而生,存放的是生成半成品单例Bean的工厂方法。
  要想说清楚三级缓存,我们先来看Springbean的生命周期,看bean的创建过程。
  核心几个类我们从AnnotationConfigApplicationContext上下文为基础来讲解bean的生命周期,AnnotationConfigApplicationContext是基于注解的上下文,看下这核心构造器。CreateanewAnnotationConfigApplicationContext,derivingbeandefinitionsfromthegivencomponentclassesandautomaticallyrefreshingthecontext。paramcomponentClassesoneormorecomponentclassesforexample,{linkConfigurationConfiguration}classespublicAnnotationConfigApplicationContext(C?。。。componentClasses){this();register(componentClasses);refresh();}
  再看refresh()publicvoidrefresh()throwsBeansException,IllegalStateException{synchronized(this。startupShutdownMonitor){StartupStepcontextRefreshthis。applicationStartup。start(spring。context。refresh);Preparethiscontextforrefreshing。prepareRefresh();Tellthesubclasstorefreshtheinternalbeanfactory。ConfigurableListableBeanFactorybeanFactoryobtainFreshBeanFactory();Preparethebeanfactoryforuseinthiscontext。prepareBeanFactory(beanFactory);try{Allowspostprocessingofthebeanfactoryincontextsubclasses。postProcessBeanFactory(beanFactory);StartupStepbeanPostProcessthis。applicationStartup。start(spring。context。beans。postprocess);Invokefactoryprocessorsregisteredasbeansinthecontext。invokeBeanFactoryPostProcessors(beanFactory);Registerbeanprocessorsthatinterceptbeancreation。registerBeanPostProcessors(beanFactory);beanPostProcess。end();Initializemessagesourceforthiscontext。initMessageSource();Initializeeventmulticasterforthiscontext。initApplicationEventMulticaster();Initializeotherspecialbeansinspecificcontextsubclasses。onRefresh();Checkforlistenerbeansandregisterthem。registerListeners();Instantiateallremaining(nonlazyinit)singletons。finishBeanFactoryInitialization(beanFactory);Laststep:publishcorrespondingevent。finishRefresh();}catch(BeansExceptionex){if(logger。isWarnEnabled()){logger。warn(Exceptionencounteredduringcontextinitializationcancellingrefreshattempt:ex);}Destroyalreadycreatedsingletonstoavoiddanglingresources。destroyBeans();Resetactiveflag。cancelRefresh(ex);Propagateexceptiontocaller。}finally{ResetcommonintrospectioncachesinSpringscore,sincewemightnoteverneedmetadataforsingletonbeansanymore。。。resetCommonCaches();contextRefresh。end();}}}
  核心主要是finishBeanFactoryInitialization(),其中beanFactory。preInstantiateSingletons()该方法中会生成所有非懒加载的单例bean。protectedvoidfinishBeanFactoryInitialization(ConfigurableListableBeanFactorybeanFactory){Initializeconversionserviceforthiscontext。if(beanFactory。containsBean(CONVERSIONSERVICEBEANNAME)beanFactory。isTypeMatch(CONVERSIONSERVICEBEANNAME,ConversionService。class)){beanFactory。setConversionService(beanFactory。getBean(CONVERSIONSERVICEBEANNAME,ConversionService。class));}RegisteradefaultembeddedvalueresolverifnoBeanFactoryPostProcessor(suchasaPropertySourcesPlaceholderConfigurerbean)registeredanybefore:atthispoint,primarilyforresolutioninannotationattributevalues。if(!beanFactory。hasEmbeddedValueResolver()){beanFactory。addEmbeddedValueResolver(strValgetEnvironment()。resolvePlaceholders(strVal));}InitializeLoadTimeWeaverAwarebeansearlytoallowforregisteringtheirtransformersearly。String〔〕weaverAwareNamesbeanFactory。getBeanNamesForType(LoadTimeWeaverAware。class,false,false);for(StringweaverAwareName:weaverAwareNames){getBean(weaverAwareName);}StopusingthetemporaryClassLoaderfortypematching。beanFactory。setTempClassLoader(null);Allowforcachingallbeandefinitionmetadata,notexpectingfurtherchanges。beanFactory。freezeConfiguration();Instantiateallremaining(nonlazyinit)singletons。beanFactory。preInstantiateSingletons();}publicvoidpreInstantiateSingletons()throwsBeansException{if(logger。isTraceEnabled()){logger。trace(Preinstantiatingsingletonsinthis);}Iterateoveracopytoallowforinitmethodswhichinturnregisternewbeandefinitions。Whilethismaynotbepartoftheregularfactorybootstrap,itdoesotherwiseworkfine。ListStringbeanNamesnewArrayList(this。beanDefinitionNames);Triggerinitializationofallnonlazysingletonbeans。。。for(StringbeanName:beanNames){RootBeanDefinitionbdgetMergedLocalBeanDefinition(beanName);if(!bd。isAbstract()bd。isSingleton()!bd。isLazyInit()){if(isFactoryBean(beanName)){ObjectbeangetBean(FACTORYBEANPREFIXbeanName);if(beaninstanceofFactoryBean){FactoryB?factory(FactoryB?)booleanisEagerIif(System。getSecurityManager()!nullfactoryinstanceofSmartFactoryBean){isEagerInitAccessController。doPrivileged((PrivilegedActionBoolean)((SmartFactoryB?)factory)::isEagerInit,getAccessControlContext());}else{isEagerInit(factoryinstanceofSmartFactoryBean((SmartFactoryB?)factory)。isEagerInit());}if(isEagerInit){getBean(beanName);}}}else{getBean(beanName);}}}Triggerpostinitializationcallbackforallapplicablebeans。。。for(StringbeanName:beanNames){ObjectsingletonInstancegetSingleton(beanName);if(singletonInstanceinstanceofSmartInitializingSingleton){StartupStepsmartInitializethis。getApplicationStartup()。start(spring。beans。smartinitialize)。tag(beanName,beanName);SmartInitializingSingletonsmartSingleton(SmartInitializingSingleton)singletonIif(System。getSecurityManager()!null){AccessController。doPrivileged((PrivilegedActionObject)(){smartSingleton。afterSingletonsInstantiated();},getAccessControlContext());}else{smartSingleton。afterSingletonsInstantiated();}smartInitialize。end();}}}
  doGetBean方法中有getSingleton、getObjectForBeanInstance、createBean比较核心,下面继续看下这代码。代码篇幅过长、简单理解下,在doGetBean方法中首先调用getSingleton方法检查单例缓存中是否有该bean,这也是我们分析三级缓存的关键,如果没有则判断当前bean的作用域是单例(singleton)还是原型(prototype),如果是单例的,再次调用getSingleton方法,不过这次的该方法是重载的一个;如果是原型的则调用createBean方法生成bean,上面几个步骤生成的beanInstance均要调用getObjectForBeanInstance方法获得bean对象。protectedTTdoGetBean(Stringname,NullableClassTrequiredType,NullableObject〔〕args,booleantypeCheckOnly)throwsBeansException{StringbeanNametransformedBeanName(name);ObjectbeanIEagerlychecksingletoncacheformanuallyregisteredsingletons。ObjectsharedInstancegetSingleton(beanName);if(sharedInstance!nullargsnull){if(logger。isTraceEnabled()){if(isSingletonCurrentlyInCreation(beanName)){logger。trace(ReturningeagerlycachedinstanceofsingletonbeanbeanNamethatisnotfullyinitializedyetaconsequenceofacircularreference);}else{logger。trace(ReturningcachedinstanceofsingletonbeanbeanName);}}beanInstancegetObjectForBeanInstance(sharedInstance,name,beanName,null);}else{Failifwerealreadycreatingthisbeaninstance:Wereassumablywithinacircularreference。if(isPrototypeCurrentlyInCreation(beanName)){thrownewBeanCurrentlyInCreationException(beanName);}Checkifbeandefinitionexistsinthisfactory。BeanFactoryparentBeanFactorygetParentBeanFactory();if(parentBeanFactory!null!containsBeanDefinition(beanName)){Notfoundcheckparent。StringnameToLookuporiginalBeanName(name);if(parentBeanFactoryinstanceofAbstractBeanFactory){return((AbstractBeanFactory)parentBeanFactory)。doGetBean(nameToLookup,requiredType,args,typeCheckOnly);}elseif(args!null){Delegationtoparentwithexplicitargs。return(T)parentBeanFactory。getBean(nameToLookup,args);}elseif(requiredType!null){NoargsdelegatetostandardgetBeanmethod。returnparentBeanFactory。getBean(nameToLookup,requiredType);}else{return(T)parentBeanFactory。getBean(nameToLookup);}}if(!typeCheckOnly){markBeanAsCreated(beanName);}StartupStepbeanCreationthis。applicationStartup。start(spring。beans。instantiate)。tag(beanName,name);try{if(requiredType!null){beanCreation。tag(beanType,requiredType::toString);}RootBeanDefinitionmbdgetMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd,beanName,args);Guaranteeinitializationofbeansthatthecurrentbeandependson。String〔〕dependsOnmbd。getDependsOn();if(dependsOn!null){for(Stringdep:dependsOn){if(isDependent(beanName,dep)){thrownewBeanCreationException(mbd。getResourceDescription(),beanName,CirculardependsonrelationshipbetweenbeanNameanddep);}registerDependentBean(dep,beanName);try{getBean(dep);}catch(NoSuchBeanDefinitionExceptionex){thrownewBeanCreationException(mbd。getResourceDescription(),beanName,beanNamedependsonmissingbeandep,ex);}}}Createbeaninstance。if(mbd。isSingleton()){sharedInstancegetSingleton(beanName,(){try{returncreateBean(beanName,mbd,args);}catch(BeansExceptionex){Explicitlyremoveinstancefromsingletoncache:Itmighthavebeenputthereeagerlybythecreationprocess,toallowforcircularreferenceresolution。Alsoremoveanybeansthatreceivedatemporaryreferencetothebean。destroySingleton(beanName);}});beanInstancegetObjectForBeanInstance(sharedInstance,name,beanName,mbd);}elseif(mbd。isPrototype()){Itsaprototypecreateanewinstance。ObjectprototypeItry{beforePrototypeCreation(beanName);prototypeInstancecreateBean(beanName,mbd,args);}finally{afterPrototypeCreation(beanName);}beanInstancegetObjectForBeanInstance(prototypeInstance,name,beanName,mbd);}else{StringscopeNamembd。getScope();if(!StringUtils。hasLength(scopeName)){thrownewIllegalStateException(NoscopenamedefinedforbeanbeanName);}Scopescopethis。scopes。get(scopeName);if(scopenull){thrownewIllegalStateException(NoScoperegisteredforscopenamescopeName);}try{ObjectscopedInstancescope。get(beanName,(){beforePrototypeCreation(beanName);try{returncreateBean(beanName,mbd,args);}finally{afterPrototypeCreation(beanName);}});beanInstancegetObjectForBeanInstance(scopedInstance,name,beanName,mbd);}catch(IllegalStateExceptionex){thrownewScopeNotActiveException(beanName,scopeName,ex);}}}catch(BeansExceptionex){beanCreation。tag(exception,ex。getClass()。toString());beanCreation。tag(message,String。valueOf(ex。getMessage()));cleanupAfterBeanCreationFailure(beanName);}finally{beanCreation。end();}}returnadaptBeanInstance(name,beanInstance,requiredType);}
  我们知道了DefaultSingletonBeanRegistry类下的getSingleton是Springbean缓存的关键,那么看下代码,Returnthe(raw)singletonobjectregisteredunderthegivenname。pChecksalreadyinstantiatedsingletonsandalsoallowsforanearlyreferencetoacurrentlycreatedsingleton(resolvingacircularreference)。parambeanNamethenameofthebeantolookforparamallowEarlyReferencewhetherearlyreferencesshouldbecreatedornotreturntheregisteredsingletonobject,or{codenull}ifnonefoundNullableprotectedObjectgetSingleton(StringbeanName,booleanallowEarlyReference){Quickcheckforexistinginstancewithoutfullsingletonlock一级缓存ObjectsingletonObjectthis。singletonObjects。get(beanName);if(singletonObjectnullisSingletonCurrentlyInCreation(beanName)){二级缓存singletonObjectthis。earlySingletonObjects。get(beanName);if(singletonObjectnullallowEarlyReference){synchronized(this。singletonObjects){ConsistentcreationofearlyreferencewithinfullsingletonlocksingletonObjectthis。singletonObjects。get(beanName);if(singletonObjectnull){singletonObjectthis。earlySingletonObjects。get(beanName);if(singletonObjectnull){三级缓存ObjectF?singletonFactorythis。singletonFactories。get(beanName);if(singletonFactory!null){singletonObjectsingletonFactory。getObject();this。earlySingletonObjects。put(beanName,singletonObject);this。singletonFactories。remove(beanName);}}}}}}returnsingletonO}
  以上就是从源码上了解三级缓存,执行流程:1。先从第一级缓存找对象,有就返回,没有就找二级缓存;
  2。找二级缓存,有就返回,没有就找三级缓存;
  3。找三级缓存,找到了,就获取对象,放到二级缓存,从三级缓存移除。3、如何解决缓存依赖问题?
  以上都是SpringBean缓存的介绍,是如何解决循环依赖的问题呢?
  我们再看一段代码protectedvoidaddSingletonFactory(StringbeanName,ObjectF?singletonFactory){Assert。notNull(singletonFactory,Singletonfactorymustnotbenull);synchronized(this。singletonObjects){判断一级缓存中不存在此对象if(!this。singletonObjects。containsKey(beanName)){直接从工厂中获取BeanobjectosingletonFactory。getObject();添加至二级缓存中this。earlySingletonObjects。put(beanName,o);this。registeredSingletons。add(beanName);}}}
  总结来说,Spring通过三级缓存实现循环依赖,来存放对象的代理工厂用于保存bean创建工厂。在遇到循环依赖时候优先通过二级缓存看是否存在依赖对象的半成品、没有则去三级缓存获取BeanFactory创建对象,创建成功之后放入到二级缓存中。
  为什么多出二级缓存呢,只要三级缓存能不能实现?
  二级缓存的目的是为了避免因为AOP创建多个对象,其中存储的是半成品的AOP的单例bean。
  能不能只要二级缓存,二级缓存也可以解决循环依赖问题啊?
  主要解决代理对象问题,假如不存在代理对象,二级缓存也是足够的。
  Spring只用二级缓存来解决循环依赖,那么所有Bean都需要在实例化完成之后就立马为其创建代理,而Spring的设计原则是会在完成属性填充、并且执行完初始化之后再为其创建代理。所以,Spring选择了三级缓存,,但是因为循环依赖的出现,导致了Spring不得不提前去创建代理,因为如果不提前创建代理对象,那么注入的就是原始对象,这样就会产生错误。
投诉 评论 转载

热爱中国美食!马布里在东北吃铁锅炖大鹅,直呼好吃!好吃近日球迷们非常喜欢的马布里马政委在中国东北参加活动,作为北控男篮的主教练,马布里在最近几年时间里一直待在中国生活,不过很可惜的是他一直没能学会太多的中文,以至于在比赛过程中没有……向日葵开机插座C1Pro体验小产品大作为,远程开机就是这么简不知道大家有没有碰到过人在外面,又临时有事需要用到家里电脑上文件的经历?这个时候你是会选择请假回家还是会选择让家里人给你处理下?不过不管你用上面那种方法,感觉都挺费事的。今天楼……中年女人别瞎穿,今夏认准这3款百搭单品,气质显瘦很减龄精致的女人一定是自信从容的,在穿衣打扮上也会有着自己独特的风格,并且对生活充满了热情。尤其是过了30岁的女人,不管工作多忙,还是带娃有多忙,都不要被生活禁锢住那颗变美的心。……鲜嫩爆汁鹅蛋腾龙客服经理的秘密食谱腾龙客服分享鹅蛋怎么做好吃将适量的枸杞、冰糖和泡发的香菇倒入装有鹅蛋的碗中。倒入适量的温水,用保鲜膜盖好碗,并在上面用牙签扎几个小洞。(美食在线客服经理)最后……希金斯再获亚军,亚军数量前无古人,布雷切尔夺冠后膜拜前辈致敬2021年12月13日凌晨,2021斯诺克苏格兰公开赛落下帷幕,连续两站排名赛闯入决赛的小和尚布雷切尔击败前辈希金斯,捧起了斯蒂芬。亨得利杯,而巫师则苦涩吞下本赛季第四个亚军的……北京媒体正式确认!中国女排传来振奋喜讯,张常宁袁心玥机会来了北京时间7月19日,中国女排传来最新消息,据北京媒体《北京日报》报道确认,女排世锦赛总共有24支球队参赛,中国女排与巴西女排,日本女排、哥伦比亚女排、阿根廷女排、捷克女排分在D……正厅级一把手落马两天后,已经卸任两年半的他被查撰文丨高语阳11月9日,山西省纪委监委消息,山西省工业和信息化厅党组成员,省小企业发展促进局党组书记、局长薛江炤接受审查调查。薛江炤曾于2017年4月至2020年2……取代马斯克,现在世界首富是他来源:参考消息网阿根廷布宜诺斯艾利斯经济新闻网12月13日发表题为《谁是贝尔纳阿尔诺?取代马斯克成为世界首富的人》的文章,全文摘编如下:根据《福布斯》杂志的全球富豪……不要再问Spring是如何解决循环依赖了1、什么是循环依赖?循环依赖主要来次三个方面,第一种A相互依赖,第二种是A依赖B,B依赖A,第三种是A依赖B,B依赖C,C依赖A。总结一句话就是对象之间形成环形依赖……时空英豪2新起点这游戏有点意思上天入地好不爽快《时空英豪2:新起点》是由THQNordic发行的游戏作品,本作发生在原作剧情的20年后,将是一部开放世界中的第三人称冒险游戏并讲述一个非线性的故事。距离备受赞誉的动作冒……王者荣耀6。23正式服更新,11位英雄调整,鲁班七号成T0射大家好,我是秋豆。S28赛季将于6。23日上线正式服,新赛季正式服的英雄调整涉及到11位英雄,鲁班七号加强,有望成T0射手,马可波罗又又又砍一刀。下面一起和秋豆看看……为何纯电没有插混和增程香?不能给诗和远方及充电等待时间过长!新能源汽车销量增幅迅猛,纯电汽车、插电混动和增程式电动三种新能源,销量增幅大不同,纯电汽车的增幅放缓,插电混动和增程式增幅超过了纯电汽车。为何越来越多人选择新能源时,更愿意选插……
糖尿病的元凶或已找到,提醒3种食物,或让血糖值飚高老话说冬补吃3宝,不把医生找,吃的是哪3宝,应该怎么吃?老照片90年代的记忆观鸟赶海拾色三种纬度打开海岛春天孩子的出生顺序与其性格有关,真的有心理学依据的,你知道吗?哈尔滨入选第九届中国夜游名城中国旅游休闲街区创新发展案例国际空间站遇麻烦,航天服漏水漏电,俄宇航员希望参观中国空间站听永不消逝的电波4K彩色修复版上映带动李白烈士故居迎来参观高宁德时代在济宁兖州正式开工建设北京冬奥组委官方辟谣选择AMD还是Intel?丨一文搞定迷你主机选购与环境搭建(三分之差输给浙江!辽篮的强,并没有写在骨子里
防蜱虫,避免与宠物亲密接触秋日穿搭怎样留住朝气学院风中长休闲西装外套2025年芯片霸主剧本英特尔已写好,情节你想不到我和弟弟差了27岁网友还以为是父子退休人员党费缴纳标准煎雨落雪拍蚊子双鱼男人配金牛女人相配吗(金牛男双鱼女座配对)孔雀草怎么扦插我又被阴阳怪气了如果受伤的是临时工人算不算工伤?拒绝降薪,如愿加盟76人!恩比德如愿以偿,你需要证明哈登是对许昌一核酸机构暂停接收核酸样本?当地回应热传聚热点网

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找美丽时装彩妆资讯历史明星乐活安卓数码常识驾车健康苹果问答网络发型电视车载室内电影游戏科学音乐整形