专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

请展开说说,SpringBeanIoCAOP循环依赖

  作者:小傅哥
  博客:https:bugstack。cn包含:Java基础,面经手册,Netty4。x,手写Spring,用Java实现JVM,重学Java设计模式,SpringBoot中间件开发,IDEA插件开发,DDD系统架构项目开发,字节码编程。。。
  沉淀、分享、成长,让自己和他人都能有所收获!一、前言
  延迟满足能给你带来什么?
  大学有四年时间,但几乎所有人都是临近毕业才发现找一份好工作费劲,尤其是我能非常熟悉的软件开发行业,即使是毕业了还需要额外花钱到培训机构,在学一遍编程技术才能出去找工作。好像在校这几年压根就没学到什么!
  就我个人而言可能是因为上学期间喜欢编程,也从师哥、师姐那里听到一些关于毕业后找工作的不容易,也了解了一些社会上对程序员开发技能的要求级别。也就是得到了这些消息,又加上自己乐于折腾,我给自己定了一个每天都能完成的小目标:红尘世界几个王,我自不服迎头上。日敲代码两百行,冲进世界五百强。
  哈哈哈,就这么每天两百行代码,一个月就是6千行,一年就是6万行,三年后开始实习就有18万行,一个应届实习生有将近20万行代码的敲击量,几乎已经可以非常熟练的完成各类简单的工作,在加上实习中对整个项目流程真正的锻炼后,找一个正经的开发工作,还是很容易的。
  而这时候找工作的容易,就来自于你一直以来的学习和沉淀,但如果你没经过这些努力,可能等毕业后就会变得非常慌乱,最后没办法只能去一些机构再学习一遍。二、面试题
  谢飞机,小记!,以前感觉Spring没啥,看过一篇getBean,我的天!
  谢飞机:面试官,最近我看了Spring的getBean发现这里好多东西,还有一个是要解决循环依赖的,这玩意面试有啥要问的吗?
  面试官:有哇,Spring是如何解决循环依赖的?
  谢飞机:嗯,通过三级缓存提前暴露对象解决的。
  面试官:可以哈,那这三个缓存里都存放了什么样的对象信息呢?
  谢飞机:一级缓存存放的是完整对象,也叫成品对象。二级缓存存放的是半成品对象,就是那些属性还没赋值的对象。三级缓存存放的是ObjectFactorylt;?类型的lambda表达式,就是这用于处理AOP循环依赖的。
  面试官:可以呀,谢飞机有所准备嘛!那如果没有三级缓存,只有二级或者一级,能解决循环依赖吗?
  谢飞机:其实我看过资料了,可以解决,只不过Spring要保证几个事情,只有一级缓存处理流程没法拆分,复杂度也会增加,同时半成品对象可能会有空指针异常。而将半成品与成品对象分开,处理起来也更加优雅、简单、易扩展。另外Spring的两大特性中不仅有IOC还有AOP,也就是基于字节码增强后的方法,该存放到哪,而三级缓存最主要,要解决的循环依赖就是对AOP的处理,但如果把AOP代理对象的创建提前,那么二级缓存也一样可以解决。但是,这就违背了Spring创建对象的原则,Spring更喜欢把所有的普通Bean都初始化完成,在处理代理对象的初始化。
  面试官:飞机,不错嘛,这次了解了不少。那问个简单的,你撸过循环依赖的解决方案?
  谢飞机:哦哦,这没有,没实践过!!!确实应该搞一下,试试。三、什么是循环依赖?1。问题描述
  了解问题的本质再分析问题,往往更利于对问题有更深入的了解和研究。所以我们在分析Spring关于循环依赖的源码之前,先要了解下什么是循环依赖。
  循环依赖分为三种,自身依赖于自身、互相循环依赖、多组循环依赖。但无论循环依赖的数量有多少,循环依赖的本质是一样的。就是你的完整创建依赖于我,而我的完整创建也依赖于你,但我们互相没法解耦,最终导致依赖创建失败。所以Spring提供了除了构造函数注入和原型注入外的,setter循环依赖注入解决方案。那么我们也可以先来尝试下这样的依赖,如果是我们自己处理的话该怎么解决。2。问题体现publicclassABTest{publicstaticvoidmain(String〔〕args){newClazzA();}}classClazzA{privateClazzBbnewClazzB();}classClazzB{privateClazzAanewClazzA();}这段代码就是循环依赖最初的模样,你中有我,我中有你,运行就报错java。lang。StackOverflowError这样的循环依赖代码是没法解决的,当你看到Spring中提供了getset或者注解,这样之所以能解决,首先是进行了一定的解耦。让类的创建和属性的填充分离,先创建出半成品Bean,再处理属性的填充,完成成品Bean的提供。3。问题处理
  在这部分的代码中就一个核心目的,我们来自己解决一下循环依赖,方案如下:publicclassCircleTest{privatefinalstaticMapString,ObjectsingletonObjectsnewConcurrentHashMap(256);publicstaticvoidmain(String〔〕args)throwsException{System。out。println(getBean(B。class)。getA());System。out。println(getBean(A。class)。getB());}privatestaticTTgetBean(ClassTbeanClass)throwsException{StringbeanNamebeanClass。getSimpleName()。toLowerCase();if(singletonObjects。containsKey(beanName)){return(T)singletonObjects。get(beanName);}实例化对象入缓存ObjectobjbeanClass。newInstance();singletonObjects。put(beanName,obj);属性填充补全对象Field〔〕fieldsobj。getClass()。getDeclaredFields();for(Fieldfield:fields){field。setAccessible(true);Classlt;?fieldClassfield。getType();StringfieldBeanNamefieldClass。getSimpleName()。toLowerCase();field。set(obj,singletonObjects。containsKey(fieldBeanName)?singletonObjects。get(fieldBeanName):getBean(fieldClass));field。setAccessible(false);}return(T)obj;}}classA{privateBb;。。。getset}classB{privateAa;。。。getset}这段代码提供了A、B两个类,互相有依赖。但在两个类中的依赖关系使用的是setter的方式进行填充。也就是只有这样才能避免两个类在创建之初不非得强依赖于另外一个对象。getBean,是整个解决循环依赖的核心内容,A创建后填充属性时依赖B,那么就去创建B,在创建B开始填充时发现依赖于A,但此时A这个半成品对象已经存放在缓存到singletonObjects中了,所以B可以正常创建,在通过递归把A也创建完整了。四、源码分析1。说说细节
  通过上面的例子我们大概了解到,A和B互相依赖时,A创建完后填充属性B,继续创建B,再填充属性A时就可以从缓存中获取了,如下:
  那这个解决事循环依赖的事放到Spring中是什么样呢?展开细节!
  虽然,解决循环依赖的核心原理一样,但要放到支撑起整个Spring中IOC、AOP特性时,就会变得复杂一些,整个处理Spring循环依赖的过程如下;
  以上就是关于Spring中对于一个有循环依赖的对象获取过程,也就是你想要的说说细节乍一看是挺多流程,但是这些也基本是你在调试代码时候必须经过的代码片段,拿到这份执行流程,再调试就非常方便了。2。处理过程
  关于本章节涉及到的案例源码分析,已更新到github:https:github。comfuzhengweiinterviewinterview31
  以下是单元测试中对AB依赖的获取Bean操作,重点在于进入getBean的源码跟进;Testpublicvoidtestalias(){BeanFactorybeanFactorynewClassPathXmlApplicationContext(springconfig。xml);BeanAbeanabeanFactory。getBean(beana,BeanA。class);logger。info(获取Bean通过别名:{},beana。getBeanb());}
  org。springframework。beans。factory。support。AbstractBeanFactory。javaOverridepublicTTgetBean(Stringname,ClassTrequiredType)throwsBeansException{returndoGetBean(name,requiredType,null,false);}从getBean进入后,获取bean的操作会进入到doGetBean。之所以这样包装一层,是因为doGetBean有很多不同入参的重载方法,方便外部操作。
  doGetBean方法protectedTTdoGetBean(finalStringname,finalClassTrequiredType,finalObject〔〕args,booleantypeCheckOnly)throwsBeansException{从缓存中获取bean实例ObjectsharedInstancegetSingleton(beanName);mbd。isSingleton()用于判断bean是否是单例模式if(mbd。isSingleton()){获取bean实例sharedInstancegetSingleton(beanName,newObjectFactoryObject(){OverridepublicObjectgetObject()throwsBeansException{try{创建bean实例,createBean返回的bean实例化好的returncreateBean(beanName,mbd,args);}catch(BeansExceptionex){destroySingleton(beanName);throwex;}}});后续的处理操作beangetObjectForBeanInstance(sharedInstance,name,beanName,mbd);}。。。返回bean实例return(T)bean;}按照在源码分析的流程图中可以看到,这一部分是从getSingleton先判断是否有实例对象,对于第一次进入是肯定没有对象的,要继续往下走。在判断mbd。isSingleton()单例以后,开始使用基于ObjectFactory包装的方式创建createBean,进入后核心逻辑是开始执行doCreateBean操作。
  doCreateBean方法protectedObjectdoCreateBean(finalStringbeanName,finalRootBeanDefinitionmbd,finalObject〔〕args)throwsBeanCreationException{创建bean实例,并将bean实例包装到BeanWrapper对象中返回instanceWrappercreateBeanInstance(beanName,mbd,args);添加bean工厂对象到singletonFactories缓存中addSingletonFactory(beanName,newObjectFactoryObject(){OverridepublicObjectgetObject()throwsBeansException{获取原始对象的早期引用,在getEarlyBeanReference方法中,会执行AOP相关逻辑。若bean未被AOP拦截,getEarlyBeanReference原样返回bean。returngetEarlyBeanReference(beanName,mbd,bean);}});try{填充属性,解析依赖关系populateBean(beanName,mbd,instanceWrapper);if(exposedObject!null){exposedObjectinitializeBean(beanName,exposedObject,mbd);}}返回bean实例returnexposedObject;}在doCreateBean方法中包括的内容较多,但核心主要是创建实例、加入缓存以及最终进行属性填充,属性填充就是把一个bean的各个属性字段涉及到的类填充进去。createBeanInstance,创建bean实例,并将bean实例包装到BeanWrapper对象中返回addSingletonFactory,添加bean工厂对象到singletonFactories缓存中getEarlyBeanReference,获取原始对象的早期引用,在getEarlyBeanReference方法中,会执行AOP相关逻辑。若bean未被AOP拦截,getEarlyBeanReference原样返回bean。populateBean,填充属性,解析依赖关系。也就是从这开始去找寻A实例中属性B,紧接着去创建B实例,最后在返回回来。
  getSingleton三级缓存protectedObjectgetSingleton(StringbeanName,booleanallowEarlyReference){从singletonObjects获取实例,singletonObjects是成品beanObjectsingletonObjectthis。singletonObjects。get(beanName);判断beanName,isSingletonCurrentlyInCreation对应的bean是否正在创建中if(singletonObjectnullisSingletonCurrentlyInCreation(beanName)){synchronized(this。singletonObjects){从earlySingletonObjects中获取提前曝光未成品的beansingletonObjectthis。earlySingletonObjects。get(beanName);if(singletonObjectnullallowEarlyReference){获取相应的bean工厂ObjectFactorylt;?singletonFactorythis。singletonFactories。get(beanName);if(singletonFactory!null){提前曝光bean实例,主要用于解决AOP循环依赖singletonObjectsingletonFactory。getObject();将singletonObject放入缓存中,并将singletonFactory从缓存中移除this。earlySingletonObjects。put(beanName,singletonObject);this。singletonFactories。remove(beanName);}}}}return(singletonObject!NULLOBJECT?singletonObject:null);}singletonObjects。get(beanName),从singletonObjects获取实例,singletonObjects是成品beanisSingletonCurrentlyInCreation,判断beanName,isSingletonCurrentlyInCreation对应的bean是否正在创建中allowEarlyReference,从earlySingletonObjects中获取提前曝光未成品的beansingletonFactory。getObject(),提前曝光bean实例,主要用于解决AOP循环依赖
  综上,是一个处理循环依赖的代码流程,这部分提取出来的内容主要为核心内容,并没与长篇大论的全部拆取出来,大家在调试的时候会涉及的比较多,尽可能要自己根据流程图操作调试几遍。3。依赖解析
  综上从我们自己去尝试解决循环依赖,学习了循环依赖的核心解决原理。又分析了Spring解决的循环依赖的处理过程以及核心源码的分析。那么接下来我们在总结下三级缓存分别不同的处理过程,算是一个总结,也方便大家理解。1。一级缓存能解决吗?
  其实只有一级缓存并不是不能解决循环依赖,就像我们自己做的例子一样。但是在Spring中如果像我们例子里那么处理,就会变得非常麻烦,而且也可能会出现NPE问题。所以如图按照Spring中代码处理的流程,我们去分析一级缓存这样存放成品Bean的流程中,是不能解决循环依赖的问题的。因为A的成品创建依赖于B,B的成品创建又依赖于A,当需要补全B的属性时A还是没有创建完,所以会出现死循环。2。二级缓存能解决吗?
  有了二级缓存其实这个事处理起来就容易了,一个缓存用于存放成品对象,另外一个缓存用于存放半成品对象。A在创建半成品对象后存放到缓存中,接下来补充A对象中依赖B的属性。B继续创建,创建的半成品同样放到缓存中,在补充对象的A属性时,可以从半成品缓存中获取,现在B就是一个完整对象了,而接下来像是递归操作一样A也是一个完整对象了。3。三级缓存解决什么?
  有了二级缓存都能解决Spring依赖了,怎么要有三级缓存呢。其实我们在前面分析源码时也提到过,三级缓存主要是解决SpringAOP的特性。AOP本身就是对方法的增强,是ObjectFactorylt;?类型的lambda表达式,而Spring的原则又不希望将此类类型的Bean前置创建,所以要存放到三级缓存中处理。其实整体处理过程类似,唯独是B在填充属性A时,先查询成品缓存、再查半成品缓存,最后在看看有没有单例工程类在三级缓存中。最终获取到以后调用getObject方法返回代理引用或者原始引用。至此也就解决了SpringAOP所带来的三级缓存问题。本章节涉及到的AOP依赖有源码例子,可以进行调试五、总结回顾本文基本以实际操作的例子开始,引导大家对循环依赖有一个整体的认识,也对它的解决方案可以上手的例子,这样对后续的关于Spring对循环依赖的解决也就不会那么陌生了。通篇全文下来大家也可以看到,三级缓存并不是非必须不可,只不过在满足Spring自身创建的原则下,是必须的。如果你可以下载Spring源码对这部分代码进行改动下,提前创建AOP对象保存到缓存中,那么二级缓存一样可以解决循环依赖问题。关于循环依赖可能并不是一个好的编码方式,如果在自己的程序中还是要尽可能使用更合理的设计模式规避循环依赖,可能这些方式会增加代码量,但在维护上会更加方便。当然这不是强制,可以根据你的需要而来。

科莫多巨蜥的毒液到底有多可怕?2009年,一名31岁的渔民安瓦尔,在印尼科莫多岛上采摘水果,结果不小心从水果树上掉了下来,刚好踩到了一只巨型蜥蜴,蜥蜴瞬间就朝他扑了过去,咬住了他的腿,之后又咬住了他的手臂,身体武汉未来的房价会涨到100000元平米吗?这个问题的答案是肯定的!以目前的趋势,未来武汉房价必然达到10万的水平,只是时间长短的问题。2010年至2017年,短短七年间,武汉的房价已经翻了3番,目前,武汉部分高端楼盘如洞庭兰州青白石片区,中央公园怎么样?兰州北拓的黄金区域,目前基础交通还跟不上建设需要,交通滞后可能会成为十四五期间兰州青白石片区发展的的最大障碍!不过就兰州地理位置和城区格局而言,青白石片区是离主城区最近的待开发区域农民为什么不在国家统计失业范围之内?中国有四个儿子,大儿子叫工人,二儿子叫子弟兵,三儿子叫公务员,四儿子叫农民,所以四儿子就没有纳入统计失业包括养老金范围,因为四儿子有金山银山还有三分地。农民有土地,这是农民可以赖以农村成立社区是什么意思?很多农村驻有村委会办公室,同时也驻有社区管理委员会办公室,特别是在城市郊区的农村和街道的农村都同时设立了村委会和社区管理委员会,很多人弄不明白是怎么回事。那农村成立社区是什么意思呢农村里的剩男,为何一剩再剩呢?到底是什么原因?男女比例失调。计划生育只要一个孩子时,受封建思想影响,都拚命要男孩,等他们长大了,很难找到媳妇。一,农村姑娘远嫁,二,女孩见少,三,彩礼高,四,剩男挣钱少。我就一大龄剩男!个人亲身抖音付费直播试水,看直播要给钱了?我们应该如何思考?使劲收,最好是家人们看的话,一分钟100块钱。毕竟粉丝听话的很。毕竟人设都设计好了打PK,卖货摆错价格,怒亏2个亿回馈粉丝。没事就怼工厂,怼员工反正就是赔钱回馈粉丝。赔完还得补交税马上就要退休了,退休工资才3650元太少了,怎么办?3600不少了。我企业工龄32年,退休时退休金只有2200,涨了这么多年还不到3000。知足常乐吧!如果身体不好,这些钱也够生活了,如果身体还可以,就找一些力所能及的工作,打打工补南宁五象新区未来的发展潜力很大吗?五象新区无法成为国家级新区!!!目前看来,五象新区的潜力也就这样了。我们对比一下贵阳的贵安新区,贵安新区的面积是1700平方公里,由贵阳市的郊区和安顺市合并得来。是全国第8个国家级如果把三峡大坝加高10米,截留更多的洪水,可行吗?我国的三峡大坝,作为当今世界上最大的水利枢纽工程,位于湖北省宜昌市上游,距下游葛洲坝水电站38公里,三峡大坝全长2309米高185米,呈梯形形状,集发电旅游航运调控洪水于一身。三峡大家有经历过亲人去世吗?是怎样走出痛苦和想念的?2018年9月1日下午3点8分,我的妻子在医院里停止了呼吸。她的眼睛没有闭上,我流着泪,帮她合上了双眼。我永远失去了我最亲近的爱人,孩子永远的失去了妈妈。一位好妻子,好女儿,好姑妈
加速落地!关于养老金,你需要知道这些个人养老金时代正式开启,你知道个人养老金是什么吗?对我们有哪些好处?哪些人群可以参与?有哪些品种可以选择呢?本篇文章就为大家一一讲解。一个人养老金是什么?简单来说,就是国家鼓励你开资讯吉利旗下远程品牌2023年完成A轮融资,未来3年市值300亿美元文懂车帝原创常思玥懂车帝原创行业12月27日,吉利旗下远程新能源商用车集团召开2023年度合作伙伴大会。在大会中,远程表示,2023年计划完成A轮融资。远程新能源商用车集团董事长周连亏16年,五粮液又要造纸作者张可心编辑陈芳前有茅台拿地,后有五粮液造纸,酒企多元化的比拼越来越卷了。近日,四川金竹纸业有限责任公司成立,注册资本3。2亿人民币,经营范围包括纸制造纸浆制造造纸专用设备制造等隆基中环硅片杀价27,光伏产业链降价却刚刚开始隆基绿能12月23日发布12月单晶硅片价格,其中单晶硅片P型M6150um厚度(166223mm)价格报4。54元,单晶硅片P型M10150um厚度(182247mm)价格报5。4科伦药业旗下川宁生物今日上市交易股价翻倍市值达230亿每经记者陈星每经编辑张海妮今日(12月27日)上午,伊犁川宁生物技术股份有限公司(以下简称川宁生物)在深交所挂牌交易,证券代码为301301,发行价为5元股。截至上午收盘时,涨10电科材料新外延材料产业基地首批硅外延和碳化硅外延下线近日,电科材料所属普兴公司新外延材料产业基地第一片硅外延和碳化硅外延相继出炉,标志着新产业基地进入试生产和验证阶段。电科材料稳步推进硅基外延产业发展,积极布局第三代半导体外延材料的论欧洲东印度公司对印度历史的影响欧洲骑兵部队一直非常昂贵,尤其是在印度,而欧洲东印度公司的吝啬董事无论如何都不赞成军事冒险永远不会批准维持骑兵部队的资金。但在印度,步兵的工资是最低限度的,他们很勇敢,并随时准备学多家上市电竞公司股价在今年下跌超50,FAZE蒸发16亿美金市值今年在电竞行业中SavvyGaming收购Faceit和ESL,以及微软宣布收购ActivisionBlizzard两大收购案可以说是轰动一时,这两笔收购让很多投资者对电竞行业报以国机精工拟定增募资不超过2。84亿元股价涨1。99来源中国经济网中国经济网北京12月27日讯今日,国机精工(002046。SZ)股价上涨,截至收盘报11。28元,涨幅1。99。国机精工昨晚披露2022年度非公开发行股票预案,本次发前11月深圳直播带货1522亿元深圳直播电商经济发展迅猛。记者昨日从深圳市商务局获悉,2022年111月,深圳直播带货279。8万场,同比增长39。6参与直播的商品网络零售量8。2亿件,形成网络零售额1522。3周迅同框张梓琳输很多!一个恨天高显小气,一个踩平底鞋大方优雅女人对于自己的身材是格外看重的,因为高矮胖瘦的不同,对于自身的气质影响力特别高,尤其是身高上的问题,很多人对于自己的小个子就非常的焦虑,不仅穿衣服很容易出现压身高的情况,就连气场也
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网