日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring.ImportSelector接口

發布時間:2025/3/15 javascript 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring.ImportSelector接口 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、關于ImportSelector接口

ImportSelector接口是至spring中導入外部配置的核心接口,在SpringBoot的自動化配置和@EnableXXX(功能性注解)都有它的存在

二、ImportSelector接口源碼

package org.springframework.context.annotation;import org.springframework.core.type.AnnotationMetadata;/*** Interface to be implemented by types that determine which @{@link Configuration}* class(es) should be imported based on a given selection criteria, usually one or more* annotation attributes.** <p>An {@link ImportSelector} may implement any of the following* {@link org.springframework.beans.factory.Aware Aware} interfaces, and their respective* methods will be called prior to {@link #selectImports}:* <ul>* <li>{@link org.springframework.context.EnvironmentAware EnvironmentAware}</li>* <li>{@link org.springframework.beans.factory.BeanFactoryAware BeanFactoryAware}</li>* <li>{@link org.springframework.beans.factory.BeanClassLoaderAware BeanClassLoaderAware}</li>* <li>{@link org.springframework.context.ResourceLoaderAware ResourceLoaderAware}</li>* </ul>** <p>ImportSelectors are usually processed in the same way as regular {@code @Import}* annotations, however, it is also possible to defer selection of imports until all* {@code @Configuration} classes have been processed (see {@link DeferredImportSelector}* for details).** @author Chris Beams* @since 3.1* @see DeferredImportSelector* @see Import* @see ImportBeanDefinitionRegistrar* @see Configuration*/ public interface ImportSelector {/*** Select and return the names of which class(es) should be imported based on* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.*/String[] selectImports(AnnotationMetadata importingClassMetadata);}

該接口文檔上說的明明白白,其主要作用是收集需要導入的配置類,如果該接口的實現類同時實現EnvironmentAware, BeanFactoryAware ,BeanClassLoaderAware或者ResourceLoaderAware,那么在調用其selectImports方法之前先調用上述接口中對應的方法,如果需要在所有的@Configuration處理完再導入時可以實現DeferredImportSelector接口。

三、例子

@Import(MyImportSelector.class) public class AppConfig { } public class MyDao {public void query(){System.out.println("query MyDao for MyImportSelect");} } public class MyImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{MyDao.class.getName()};} } public class TestImpo {public static void main(String[] args) {AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(AppConfig.class);MyDao myDao = ctx.getBean(MyDao.class);myDao.query();} } 運行打印 query MyDao for MyImportSelect

從上面的例子看,盡管程序上沒有把MyImportSelect類放到Spring容器中,也沒有把MyDao放到Spring容器中,但是在測試上就可以把MyDao從容器中拿出來,并且正常執行。不知道大家看到這里有什么感覺,到這里我其實是有疑問的。我這么做有個卵用噻。我是有病吧,直接把類上加個@Component注冊進去不香嗎?所以這個ImportSelector把程序搞這么復雜是有毛病吧,把簡單的功能搞這么復雜。

四、ImportSelector真正的作用

其實Spring既然這么設計,那肯定是有用的。那么有什么用呢?設想這樣一個場景,如果有些功能我們并不需要Spring在一開始就加載進去,而是需要Spring幫助我們把這些功能動態加載進去,這時候這個ImportSelector的作用就來了。我們完全可以把實現這個接口的類做成一個開關,用來開啟或者關閉某一個或者某些功能類。比如說我們上面的例子MyDao,假設這個MyDao實現的功能是一個擴展功能,在正式的生產上不一定用的到。如果說一個包下有100個類,那么使用掃描去屏蔽這個類就很麻煩,但是屏蔽這個類用ImportSelector去做就很容易了。下次如果需要用到了,我再放開這個開關,直接可以使用MyDao的功能了,這樣就做到了一個靈活的功能掌控。

  • 改造例子
@Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Import(MyImportSelector.class) public @interface EnableMySelector { }@EnableMySelector //該注解引入MyImportSelector public class AppConfig { }public class TestImpo {public static void main(String[] args) {AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(AppConfig.class);MyDao myDao = null;//根據bean中是否有MyDao類型進行控制try {myDao = ctx.getBean(MyDao.class);myDao.query();} catch (BeansException e) {e.printStackTrace();}} }

其實Spring中那么多的EnableXXXX的注解底層就是這樣的原理

五、ImportSelector源碼分析

我們可以來看一下ConfigurationClassParser這個類的processImports方法

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,Collection<SourceClass> importCandidates, boolean checkForCircularImports) {if (importCandidates.isEmpty()) {return;}if (checkForCircularImports && isChainedImportOnStack(configClass)) {this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));}else {this.importStack.push(configClass);try {for (SourceClass candidate : importCandidates) {            //對ImportSelector的處理if (candidate.isAssignable(ImportSelector.class)) {// Candidate class is an ImportSelector -> delegate to it to determine importsClass<?> candidateClass = candidate.loadClass();ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);ParserStrategyUtils.invokeAwareMethods(selector, this.environment, this.resourceLoader, this.registry);if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {                //如果為延遲導入處理則加入集合當中this.deferredImportSelectors.add(new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));}else {                //根據ImportSelector方法的返回值來進行遞歸操作String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);processImports(configClass, currentSourceClass, importSourceClasses, false);}}else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {// Candidate class is an ImportBeanDefinitionRegistrar ->// delegate to it to register additional bean definitionsClass<?> candidateClass = candidate.loadClass();ImportBeanDefinitionRegistrar registrar =BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);ParserStrategyUtils.invokeAwareMethods(registrar, this.environment, this.resourceLoader, this.registry);configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());}else {              // 如果當前的類既不是ImportSelector也不是ImportBeanDefinitionRegistar就進行@Configuration的解析處理// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->// process it as an @Configuration classthis.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());processConfigurationClass(candidate.asConfigClass(configClass));}}}catch (BeanDefinitionStoreException ex) {throw ex;}catch (Throwable ex) {throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +configClass.getMetadata().getClassName() + "]", ex);}finally {this.importStack.pop();}}}

在這里我們可以看到ImportSelector接口的返回值會遞歸進行解析,把解析到的類全名按照@Configuration進行處理

六、連帶說一下DeferredImportSelector

這個是看Spring源碼的時候發現的,直接翻譯就是延時加載ImportSelector,實現這個接口的類,將會在@Configuration后面被加載,用法什么的和ImportSelector功能基本一樣。因為用的比較稀有就不多做解釋了,僅僅作為一個只是擴展點介紹下。在ConfigurationClassParser中會有一個判斷,是不是這個接口,如果是就會放到后面解析。以下摘自源碼:

org.springframework.context.annotation.ConfigurationClassParser#processImports //這里攔截了DeferredImportSelector然后使用handle() if (selector instanceof DeferredImportSelector) {this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); }

進入handle()方法,發現和這個接口相關的都被加入了一個deferredImportSelectors的list中。

public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);if (this.deferredImportSelectors == null) {DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();handler.register(holder);handler.processGroupImports();}else {//加入到了一個ArrayList中this.deferredImportSelectors.add(holder);} }

最終這個ArrayList在parse()方法的最后被處理了

org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set<org.springframework.beans.factory.config.BeanDefinitionHolder>)public void parse(Set<BeanDefinitionHolder> configCandidates) {//根據BeanDefinition的類型做不同的處理,一般都會調用ConfigurationClassParser.parse()進行解析for (BeanDefinitionHolder holder : configCandidates) {BeanDefinition bd = holder.getBeanDefinition(); //拿出BeanDefinitiontry {if (bd instanceof AnnotatedBeanDefinition) { // 判斷是不是加了注解的// 解析注解對象,并且把解析出來的bd方法map中,但是這里的bd指的的普通的// 普通和不普通的怎么區分。比如@Bean和各種beanFactoryPostProcessor得到的bean//如果被加了注解,又調用了一個parse()方法parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());}else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());}else {parse(bd.getBeanClassName(), holder.getBeanName());}}catch (BeanDefinitionStoreException ex) {throw ex;}catch (Throwable ex) {throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);}}//處理,而此時上面其他的Import已經處理完了this.deferredImportSelectorHandler.process(); } 與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的Spring.ImportSelector接口的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: www.爱色av.com | 总裁边开会边做小娇妻h | 久久一级电影 | 一本之道高清无码视频 | 丰满熟女人妻一区二区三 | 国产在线精品一区二区 | 亚洲图片在线播放 | 国产调教| 色妞网| 韩国一区二区三区在线观看 | 理论片午夜| 日韩成人高清视频 | 黄色成人免费网站 | 日本色妞 | 国产69熟| 国产福利社 | 欧美成人性生活片 | 日本成人综合 | 国产青草视频在线观看 | 日韩精品久久久久久久电影99爱 | 青青青手机视频在线观看 | 日韩免费影院 | 在线免费观看av网址 | 国产成年网站 | 亚洲精品第二页 | 在线看黄色网址 | 亚洲一久久 | 最新av免费 | 亚洲激情图片区 | www.色呦呦 | 欧美日韩免费观看一区=区三区 | 男男play视频 | 日韩精品一区在线观看 | 日韩www.| 夜夜操天天干 | 日韩在线免费看 | 亚洲中文字幕一区 | 亚洲乱码在线观看 | 最新福利在线 | 精品人妻无码一区二区三 | 91成人动漫 | 人人精品久久 | 99在线无码精品入口 | 国产精品欧美一区喷水 | 日批在线观看 | 欧美毛片网站 | www.九色| 蜜桃导航-精品导航 | 欧美自拍视频在线观看 | 亚洲欧美在线综合 | 密臀av一区二区 | 91欧美一区| 丰满大乳少妇在线观看网站 | 黄色精品网站 | 国产亚洲综合av | 久久久精品日本 | 久久精品国产亚洲av麻豆蜜芽 | 亚洲一卡二卡在线观看 | 四虎影视永久免费观看 | 天天躁日日躁狠狠躁免费麻豆 | 日本视频网 | 俺也去婷婷 | 日韩欧美中文字幕一区二区 | 99免费国产 | 亚洲在线一区二区三区 | 黑人一区二区三区四区五区 | 男生舔女生的屁股 | 色屋在线 | 欧美呦呦呦| 黄色福利社 | 九九热在线视频播放 | 成人尹人 | 欧美成人高潮一二区在线看 | 欧美一区成人 | 91美女免费看 | 日韩激情影院 | 毛片基地在线播放 | 成人伊人 | 丰满孕妇性春猛交xx大陆 | 污视频在线观看免费 | 日韩在线观看视频网站 | 玖玖在线观看 | 中文字幕在线观看第二页 | 男人操女人动态图 | 在线观看中文字幕亚洲 | 日本三级在线视频 | 久久久久综合网 | 亚洲二区视频 | 亚洲一区二区三区av无码 | 激情欧美一区二区免费视频 | 亚洲一级中文字幕 | 欧美天天性影院 | 成人免费无码大片a毛片 | 天天综合人人 | 国产精品久久久久久免费免熟 | 国产精品69久久久久 | 日韩在线资源 | 黄色av网站在线免费观看 | 朝鲜一级黄色片 |