临汾山东漯河饰品美体美文
投稿投诉
美文创意
爱情通信
用品婚姻
爱好看病
美体软件
影音星座
瑜伽周边
星座办公
饰品塑形
搞笑减肥
幼儿两性
智家潮品
漯河衢州
兴义眉山
桂林阳泉
玉溪简阳
山东遂宁
永城新余
梧州洛阳
泸州温州
临汾清远
营口常熟
浙江大连
桐乡宜昌

ImportSelector与DeferredImportS

4月20日 天浪楼投稿
  欢迎访问我的GitHub
  这里分类和汇总了欣宸的全部原创(含配套源码):https:github。comzq2599blogdemos在使用Import注解来注册bean的时候,Import注解的值可以是ImportSelector或者DeferredImportSelector的实现类,spring容器会实例化这个实现类,并执行其selectImports方法,那么问题来了:ImportSelector和DeferredImportSelector的区别在哪里,我们自定义Imort逻辑的时候该选择哪个呢?本文通过分析相关的spring源码来查找答案;全文概览本文由以下几部分组成:看官方文档;分析spring源码中对这两个接口的处理;实战验证;看官方文档先看官方文档看起,我选择了4。3。9版本在线文档(这是个Release版),地址:https:docs。spring。iospringdocs4。3。19。RELEASEjavadocapi原文:AvariationofImportSelectorthatrunsafterallConfigurationbeanshavebeenprocessed。ThistypeofselectorcanbeparticularlyusefulwhentheselectedimportsareConditional。ImplementationscanalsoextendtheOrderedinterfaceorusetheOrderannotationtoindicateaprecedenceagainstotherDeferredImportSelectors。我的理解:DeferredImportSelector是ImportSelector的一个扩展;ImportSelector实例的selectImports方法的执行时机,是在Configguration注解中的其他逻辑被处理之前,所谓的其他逻辑,包括对ImportResource、Bean这些注解的处理(注意,这里只是对Bean修饰的方法的处理,并不是立即调用Bean修饰的方法,这个区别很重要!);DeferredImportSelector实例的selectImports方法的执行时机,是在Configguration注解中的其他逻辑被处理完毕之后,所谓的其他逻辑,包括对ImportResource、Bean这些注解的处理;DeferredImportSelector的实现类可以用Order注解,或者实现Ordered接口来对selectImports的执行顺序排序;分析spring源码中对这两个接口的处理接下来看看源码:在springframework4。1。8。RELEASE工程中找到类ConfigurationClassParser。java,这里面有处理配置类的主要逻辑;找到方法parse(SetconfigCandidates):publicvoidparse(SetBeanDefinitionHolderconfigCandidates){this。deferredImportSelectorsnewLinkedListDeferredImportSelectorHolder();检查每个bean的定义for(BeanDefinitionHolderholder:configCandidates){BeanDefinitionbdholder。getBeanDefinition();try{if(bdinstanceofAnnotatedBeanDefinition){对于每个有注解的类,都执行方法parse(AnnotationMetadatametadata,StringbeanName)parse(((AnnotatedBeanDefinition)bd)。getMetadata(),holder。getBeanName());}elseif(bdinstanceofAbstractBeanDefinition((AbstractBeanDefinition)bd)。hasBeanClass()){parse(((AbstractBeanDefinition)bd)。getBeanClass(),holder。getBeanName());}else{parse(bd。getBeanClassName(),holder。getBeanName());}}catch(BeanDefinitionStoreExceptionex){}catch(Exceptionex){thrownewBeanDefinitionStoreException(Failedtoparseconfigurationclass〔bd。getBeanClassName()〕,ex);}}最后再处理DeferredImportSelector的实现类processDeferredImportSelectors();}
  复制代码由以上代码可以大致看出DeferredImportSelector的实现类被最后放在processDeferredImportSelectors方法中处理,那么前面的parse(AnnotationMetadatametadata,StringbeanName)做了些什么呢?继续看;展开方法parse(AnnotationMetadatametadata,StringbeanName)里面,是执行processConfigurationClass方法;再展开processConfigurationClass方法,看到核心逻辑是调用doProcessConfigurationClass方法,展开看看:protectedfinalSourceClassdoProcessConfigurationClass(ConfigurationClassconfigClass,SourceClasssourceClass)throwsIOException{为了聚焦Import相关处理,此处略去部分不相关代码,不在这里展示了。。。。。。处理Import注解processImports(configClass,sourceClass,getImports(sourceClass),true);处理ImportResource注解if(sourceClass。getMetadata()。isAnnotated(ImportResource。class。getName())){AnnotationAttributesimportResourceAnnotationConfigUtils。attributesFor(sourceClass。getMetadata(),ImportResource。class);String〔〕resourcesimportResource。getStringArray(value);C?extendsBeanDefinitionReaderreaderClassimportResource。getClass(reader);for(Stringresource:resources){StringresolvedResourcethis。environment。resolveRequiredPlaceholders(resource);configClass。addImportedResource(resolvedResource,readerClass);}}处理Bean注解,注意是处理注解,不是执行Bean修饰的方法SetMethodMetadatabeanMethodssourceClass。getMetadata()。getAnnotatedMethods(Bean。class。getName());for(MethodMetadatamethodMetadata:beanMethods){configClass。addBeanMethod(newBeanMethod(methodMetadata,configClass));}处理Configuration类的父类,外面在调用doProcessConfigurationClass方法的时有迭代处理,确保所有父类的注解都会被处理if(sourceClass。getMetadata()。hasSuperClass()){StringsuperclasssourceClass。getMetadata()。getSuperClassName();if(!superclass。startsWith(java)!this。knownSuperclasses。containsKey(superclass)){this。knownSuperclasses。put(superclass,configClass);Superclassfound,returnitsannotationmetadataandrecursereturnsourceClass。getSuperClass();}}再也没有父类了,返回null表示当前Configuration处理完毕}
  复制代码根据上述代码分析,可以梳理出下图中的逻辑:
  现在需要再看看processImports和processDeferredImportSelectors这两个方法的具体代码;先看processImports方法:privatevoidprocessImports(ConfigurationClassconfigClass,SourceClasscurrentSourceClass,CollectionSourceClassimportCandidates,booleancheckForCircularImports)throwsIOException{if(importCandidates。isEmpty()){}if(checkForCircularImportsthis。importStack。contains(configClass)){this。problemReporter。error(newCircularImportProblem(configClass,this。importStack));}else{this。importStack。push(configClass);try{for(SourceClasscandidate:importCandidates){如果是ImportSelector接口的实现类,就在此处理if(candidate。isAssignable(ImportSelector。class)){CandidateclassisanImportSelectordelegatetoittodetermineimportsC?candidateClasscandidate。loadClass();实例化这些ImportSelector的实现类ImportSelectorselectorBeanUtils。instantiateClass(candidateClass,ImportSelector。class);如果这实现类还实现了BeanFactoryAware、EnvironmentAware这些接口,就要先执行这些接口中声明的方法invokeAwareMethods(selector);如果这个实现类也实现了DeferredImportSelector接口,就被加入到集合deferredImportSelectors中if(this。deferredImportSelectors!nullselectorinstanceofDeferredImportSelector){this。deferredImportSelectors。add(newDeferredImportSelectorHolder(configClass,(DeferredImportSelector)selector));}else{注意,这一行是关键代码!!!执行实现类的selectImports方法String〔〕importClassNamesselector。selectImports(currentSourceClass。getMetadata());CollectionSourceClassimportSourceClassesasSourceClasses(importClassNames);processImports(configClass,currentSourceClass,importSourceClasses,false);}}此处略去的和ImportSelector不相关的逻辑代码。。。。。。。。。}}catch(BeanDefinitionStoreExceptionex){}catch(Exceptionex){thrownewBeanDefinitionStoreException(Failedtoprocessimportcandidatesforconfigurationclass〔configClass。getMetadata()。getClassName()〕,ex);}finally{this。importStack。pop();}}}
  复制代码以上代码有两个关键点:第一、当前被处理的类,如果实现了DeferredImportSelector接口,就被加入到集合deferredImportSelectors中;第二、当前被处理的类,如果没有实现DeferredImportSelector接口,但是实现了ImportSelector接口,就被执行selectImports方法;接下来看看processDeferredImportSelectors方法的源码,提前推测应该是处理集合deferredImportSelectors中的所有类,这些类都实现了DeferredImportSelector接口:privatevoidprocessDeferredImportSelectors(){ListDeferredImportSelectorHolderdeferredImportsthis。deferredImportSthis。deferredImportS按照Order注解或者Ordered接口进行排序Collections。sort(deferredImports,DEFERREDIMPORTCOMPARATOR);for(DeferredImportSelectorHolderdeferredImport:deferredImports){ConfigurationClassconfigClassdeferredImport。getConfigurationClass();try{此处是关键代码,执行DeferredImportSelector实现类的selectImports方法String〔〕importsdeferredImport。getImportSelector()。selectImports(configClass。getMetadata());processImports(configClass,asSourceClass(configClass),asSourceClasses(imports),false);}catch(BeanDefinitionStoreExceptionex){}catch(Exceptionex){thrownewBeanDefinitionStoreException(Failedtoprocessimportcandidatesforconfigurationclass〔configClass。getMetadata()。getClassName()〕,ex);}}}
  复制代码至此,源码分析完毕了,从代码可以很清晰的看出ImportSelector与DeferredImportSelector的区别,就是selectImports方法执行时机有差别,这个差别期间,spring容器对此Configguration类做了些其他的逻辑:包括对ImportResource、Bean这些注解的处理(注意,这里只是对Bean修饰的方法的处理,并不是立即调用Bean修饰的方法,这个区别很重要!);实战验证接下来到了实战验证的环节了,本次实战的内容是创建一个springboot工程,在里面自定义三个ImportSelector接口的实现类,如果您不想敲代码,也可以去github下载源码,地址和链接信息如下表所示:
  这个git项目中有多个文件夹,本章源码在文件夹customizeimportselector下,如下图红框所示:
  开始编码吧:我们创建三个ImportSelector的实现类来检查其先后顺序,三个Selector类简介如下表,有两个是DeferredImportSelector的实现类,一个是ImportSelector的实现类,每个Selector负责向spring容器注册一种实例:
  基于maven创建springboot框架的web工程,pom。xml内容如下:?xmlversion1。0encodingUTF8?projectxmlnshttp:maven。apache。orgPOM4。0。0xmlns:xsihttp:www。w3。org2001XMLSchemainstancexsi:schemaLocationhttp:maven。apache。orgPOM4。0。0http:maven。apache。orgxsdmaven4。0。0。xsdmodelVersion4。0。0modelVersiongroupIdcom。bolingcavalrygroupIdcustomizeimportselectorartifactIdversion0。0。1SNAPSHOTversionpackagingjarpackagingnamecustomizeimportselectornamedescriptionDemoprojectforSpringBootdescriptionparentgroupIdorg。springframework。bootgroupIdspringbootstarterparentartifactIdversion1。5。9。RELEASEversionrelativePath!lookupparentfromrepositoryparentpropertiesproject。build。sourceEncodingUTF8project。build。sourceEncodingproject。reporting。outputEncodingUTF8project。reporting。outputEncodingjava。version1。8java。versionpropertiesdependenciesdependencygroupIdorg。springframework。bootgroupIdspringbootstarterwebartifactIddependencydependencygroupIdorg。springframework。bootgroupIdspringbootstartertestartifactIdscopetestscopedependencydependenciesbuildpluginsplugingroupIdorg。springframework。bootgroupIdspringbootmavenpluginartifactIdpluginpluginsbuildproject
  复制代码创建三个接口CustomizeService1、CustomizeService2、CustomizeService3,第一个源码如下,另外两个除了类名,其余部分一样:packagecom。bolingcavalry。customizeimportselector。publicinterfaceCustomizeService1{voidexecute();}
  复制代码创建三个类,分别实现上面的三个接口,也是除了类名其余部分一样:packagecom。bolingcavalry。customizeimportselector。service。importcom。bolingcavalry。customizeimportselector。service。CustomizeService1;publicclassCustomizeServiceImpl1implementsCustomizeService1{publicCustomizeServiceImpl1(){System。out。println(construct:this。getClass()。getSimpleName());}Overridepublicvoidexecute(){System。out。println(execute:this。getClass()。getSimpleName());}}
  复制代码创建CustomizeImportSelector1:packagecom。bolingcavalry。customizeimportselector。importorg。springframework。context。annotation。DeferredImportSimportorg。springframework。context。annotation。ImportSimportorg。springframework。core。annotation。Oimportorg。springframework。core。type。AnnotationMOrder(102)publicclassCustomizeImportSelector1implementsDeferredImportSelector{OverridepublicString〔〕selectImports(AnnotationMetadataannotationMetadata){System。out。println(selectImports:this。getClass()。getSimpleName());returnnewString〔〕{com。bolingcavalry。customizeimportselector。service。impl。CustomizeServiceImpl1};}}
  复制代码创建CustomizeImportSelector2:packagecom。bolingcavalry。customizeimportselector。importorg。springframework。context。annotation。DeferredImportSimportorg。springframework。core。annotation。Oimportorg。springframework。core。type。AnnotationMOrder(101)publicclassCustomizeImportSelector2implementsDeferredImportSelector{OverridepublicString〔〕selectImports(AnnotationMetadataannotationMetadata){System。out。println(selectImports:this。getClass()。getSimpleName());returnnewString〔〕{com。bolingcavalry。customizeimportselector。service。impl。CustomizeServiceImpl2};}}
  复制代码创建CustomizeImportSelector3,实现的是ImportSelector接口:packagecom。bolingcavalry。customizeimportselector。importorg。springframework。context。annotation。ImportSimportorg。springframework。core。annotation。Oimportorg。springframework。core。type。AnnotationMpublicclassCustomizeImportSelector3implementsImportSelector{OverridepublicString〔〕selectImports(AnnotationMetadataannotationMetadata){System。out。println(selectImports:this。getClass()。getSimpleName());returnnewString〔〕{com。bolingcavalry。customizeimportselector。service。impl。CustomizeServiceImpl3};}}
  复制代码创建配置类,将CustomizeImportSelector1、CustomizeImportSelector2、CustomizeImportSelector3全部用Import注解引入:packagecom。bolingcavalry。importcom。bolingcavalry。customizeimportselector。selector。CustomizeImportSelector1;importcom。bolingcavalry。customizeimportselector。selector。CustomizeImportSelector2;importcom。bolingcavalry。customizeimportselector。selector。CustomizeImportSelector3;importorg。springframework。context。annotation。Cimportorg。springframework。context。annotation。IConfigurationImport({CustomizeImportSelector1。class,CustomizeImportSelector2。class,CustomizeImportSelector3。class})publicclassSysConfig{}
  复制代码创建启动类CustomizeimportselectorApplication。java:packagecom。bolingcavalry。importorg。springframework。boot。SpringAimportorg。springframework。boot。autoconfigure。SpringBootASpringBootApplicationpublicclassCustomizeimportselectorApplication{publicstaticvoidmain(String〔〕args){SpringApplication。run(CustomizeimportselectorApplication。class,args);}}
  复制代码启动应用,可见输入信息如下:2018090915:43:45。790INFO15364〔main〕c。b。c。CustomizeimportselectorApplication:StartingCustomizeimportselectorApplicationonDESKTOP82CCEBNwithPID15364(D:githubblogdemoscustomizeimportselectorargetclassesstartedby12167inD:githubblogdemoscustomizeimportselector)2018090915:43:45。791INFO15364〔main〕c。b。c。CustomizeimportselectorApplication:Noactiveprofileset,fallingbacktodefaultprofiles:default2018090915:43:45。825INFO15364〔main〕ationConfigEmbeddedWebApplicationContext:Refreshingorg。springframework。boot。context。embedded。AnnotationConfigEmbeddedWebApplicationContext641147d0:startupdate〔SunSep0915:43:45GMT08:002018〕;rootofcontexthierarchyselectImports:CustomizeImportSelector3selectImports:CustomizeImportSelector2selectImports:CustomizeImportSelector12018090915:43:46。425INFO15364〔main〕s。b。c。e。t。TomcatEmbeddedServletContainer:Tomcatinitializedwithport(s):8080(http)2018090915:43:46。430INFO15364〔main〕o。apache。catalina。core。StandardService:Startingservice〔Tomcat〕2018090915:43:46。431INFO15364〔main〕org。apache。catalina。core。StandardEngine:StartingServletEngine:ApacheTomcat8。5。232018090915:43:46。493INFO15364〔oststartStop1〕o。a。c。c。C。〔Tomcat〕。〔localhost〕。〔〕:InitializingSpringembeddedWebApplicationContext2018090915:43:46。493INFO15364〔oststartStop1〕o。s。web。context。ContextLoader:RootWebApplicationContext:initializationcompletedin670ms2018090915:43:46。569INFO15364〔oststartStop1〕o。s。b。w。servlet。ServletRegistrationBean:Mappingservlet:dispatcherServletto〔〕2018090915:43:46。572INFO15364〔oststartStop1〕o。s。b。w。servlet。FilterRegistrationBean:Mappingfilter:characterEncodingFilterto:〔〕2018090915:43:46。572INFO15364〔oststartStop1〕o。s。b。w。servlet。FilterRegistrationBean:Mappingfilter:hiddenHttpMethodFilterto:〔〕2018090915:43:46。572INFO15364〔oststartStop1〕o。s。b。w。servlet。FilterRegistrationBean:Mappingfilter:httpPutFormContentFilterto:〔〕2018090915:43:46。572INFO15364〔oststartStop1〕o。s。b。w。servlet。FilterRegistrationBean:Mappingfilter:requestContextFilterto:〔〕construct:CustomizeServiceImpl1construct:CustomizeServiceImpl2construct:CustomizeServiceImpl3
  复制代码从上述信息可以看出:首先、三个selector实现类的selectImports方法执行顺序符合预期:先执行ImportSelector实现类的,再执行DeferredImportSelector实现类的,并且DeferredImportSelector实现类的执行顺序会按照Order的设置从小到大执行;其次、CustomizeServiceImpl1、CustomizeServiceImpl2、CustomizeServiceImpl3的实例化顺序并未受到影响;至此,ImportSelector与DeferredImportSelector的区别已经分析和验证完毕,随着对Configuration初始化处理逻辑的深入了解,我们可以定制出更灵活强大的配置逻辑,以符合业务需求;欢迎关注InfoQ:程序员欣宸
  学习路上,你不孤单,欣宸原创一路相伴。。。
投诉 评论

陈晓旭的林黛玉绝版照片,仅此一张,87红楼梦中从未出现87版《红楼梦》是一部经典之作,是中国电视史上的绝妙篇章,无论是演员,妆容,服装,还是音乐,道具和细节,30多年过去了,依旧让我们叹为观止。每一帧画面,都那么美,每一个镜……什么文案让你想到了自己?1。等风来,不如追风去2。所有花都为你开,所有景物也为了你安排,我们是如此的不同,肯定前世就已经深爱过3。不够真诚是危险的,太真诚则绝对是致命的4。悲悯不是为……曝芯片堆叠技术华为P60Pro,华为P50跌至超冰点价,网友曝光芯片堆叠技术加持全新华为P60Pro王者归来版除了少了5G之外,曝光芯片堆叠技术加持全新华为P60Pro王者归来版其余配置都拉满,曝光芯片堆叠技术加持全新华为P60Pro王……顶级mmorpg游戏,混沌与秩序的新手升级攻略新手村开始就按流程做任务升级到10级左右,到了10级后打开新手礼包会送一个监狱副本的传送符,这个时候就可以快速升级了。建议升到15级左右再去打,战士职业单刷容易,其他职业……正式离队!广东宏远名将无球可打,离开CBA赛场北京时间8月18日,这个休赛期,不少球队都开始进行裁员,主要是因为上一个赛季,不少的CBA俱乐部都出现亏损的情况,因为新冠肺炎疫情的影响,CBA各大俱乐部为了长远发展,都开始精……周通梅里达非常优秀我们私下都很佩服他张卫杨帆很自责直播吧8月17日讯中超联赛第13轮,天津津门虎22战平长春亚泰,其中周通梅开二度。在接受《体坛新视野》采访时,周通谈到了梅开二度的感受和目前球队的情况。谈梅开二度周……ampampquot贵人相助ampampquot倪妮截胡杨幂杨幂马不停蹄跪舔GUCCI三年也抵不上倪妮的从天而降2017年倪妮被GUCCI官宣成为代言人自此杨幂的舔狗生涯彻底结束三年前年杨幂产后复出第一件事……即热式电热水器能即开即热,体积又小,为什么很多人说是坑?由于人们对生活品质的追求,各式各类的家电都在不断地更新迭代,而我们今天要聊的热水器也是如此。现如今,相信大多数人家里使用的热水器都还是储水式的。由于容量受限,储水式……李宁体育不当言论惹怒广东,刘晓宇遭北京清洗,曾凡博试训尼克斯就在刚不久,作为CBA赞助商的李宁又闹出了幺蛾子,在旗下的社交媒体号李宁体育因为在评论区公开侮辱广东队而招致广东上下甚至球迷的口诛笔伐。在李宁体育一条标题为我投的不是篮,……别人家的好用的网络电视盒子,我们自己也是可以拥有的每一次买网络电视盒子我们都会去进行一些比较选择最优的适合自己家里使用的电视盒子,仅仅是一个简单的一件事,但也是极为不好做,不能选到最优的电视盒子,也因此小编才会要说一说那些小编……林业生物质能源产业迎来巨大发展机遇文段劼李海英贾黎明近期,国家发改委连续发布了《十四五生物经济发展规划》(以下简称《生物经济规划》)和《十四五可再生能源发展规划》(以下简称《可再生能源规划》)。《生物经济……ImportSelector与DeferredImportS欢迎访问我的GitHub这里分类和汇总了欣宸的全部原创(含配套源码):https:github。comzq2599blogdemos在使用Import注解来注册bean的……
资讯宝马更新数字钥匙,苹果和安卓系统可跨平台共享但愿人间无恙是吴奇隆整容了吗?前妻马雅苏还是那样,而他却像换了一个人3场比赛,40助0失误!东部保罗诞生,湖人亮出杀手锏仍输球羽毛球世界巡回赛总决赛陈清晨贾一凡胜张殊贤郑雨边界被打破了全球各地的降雨都无法安全饮用FVM上的商业模式散文十二月,心有温暖,静好安然有没有必要为了一个男人去到一个你没有去过的城市?焦虑失眠?张仲景最爱用滋阴的百合,可惜很多人都没吃对峨眉山雷洞坪滑雪场正式开滑十三生笑祝贺北京冬奥会开闭幕式等IP荣获2021十大年度国家扩香石是什么材料做的扩香石的应用营收净利双增股价大跳水,天齐锂业也难逃下行周期李克强主持召开国务院常务会议下一站是幸福贺灿阳有感情戏吗下一站是幸福贺灿阳和蔡敏敏在一起《美丽的小兴安岭》教学反思作文自然堂的护肤品怎么样自然堂护肤系列分析师造句用分析师造句大全(稳字当头抓落实)重点行业稳健恢复巩固工业经济企稳势头你会搂着小猫睡觉吗胜似亲人榛子可以用烤箱烤吗?用烤箱烤榛子怎么烤?

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找