亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Java > 正文

Springboot @Import 詳解

2024-07-14 08:42:57
字體:
來源:轉載
供稿:網友

SpringBoot 的 @Import 用于將指定的類實例注入之Spring IOC Container中。 

今天抽空在仔細看了下Springboot 關于 @Import 的處理過程, 記下來以后看。

1. @Import

先看Spring對它的注釋 (文檔貼過來的), 總結下來作用就是和xml配置的 <import />標簽作用一樣,允許通過它引入 @Configuration 注解的類 (java config), 引入ImportSelector接口(這個比較重要, 因為要通過它去判定要引入哪些@Configuration) 和 ImportBeanDefinitionRegistrar 接口的實現, 也包括 @Component注解的普通類。

但是如果要引入另一個xml 文件形式配置的 bean, 則需要通過 @ImportResource 注解。

/** * Indicates one or more {@link Configuration @Configuration} classes to import. * * <p>Provides functionality equivalent to the {@code <import/>} element in Spring XML. * Allows for importing {@code @Configuration} classes, {@link ImportSelector} and * {@link ImportBeanDefinitionRegistrar} implementations, as well as regular component * classes (as of 4.2; analogous to {@link AnnotationConfigApplicationContext#register}). * * <p>{@code @Bean} definitions declared in imported {@code @Configuration} classes should be * accessed by using {@link org.springframework.beans.factory.annotation.Autowired @Autowired} * injection. Either the bean itself can be autowired, or the configuration class instance * declaring the bean can be autowired. The latter approach allows for explicit, IDE-friendly * navigation between {@code @Configuration} class methods. * * <p>May be declared at the class level or as a meta-annotation. * * <p>If XML or other non-{@code @Configuration} bean definition resources need to be * imported, use the {@link ImportResource @ImportResource} annotation instead. * * @author Chris Beams * @author Juergen Hoeller * @since 3.0 * @see Configuration * @see ImportSelector * @see ImportResource */@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Import {  /**   * {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}   * or regular component classes to import.   */  Class<?>[] value();}

2. ImportSelector

因為 @Import 的實現有很多時候需要借助 ImportSelector 接口, 所以我們再看下這個接口的描述, 總結下來就是需要通過這個接口的實現去決定要引入哪些 @Configuration。 它如果實現了以下四個Aware 接口, 那么spring保證會在調用它之前先調用Aware接口的方法。

至于為什么要保證調用Aware, 我個人覺得應該是你可以通過這些Aware去感知系統里邊所有的環境變量, 從而決定你具體的選擇邏輯。

/** * 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);}

3. Springboot 對@Import注解的處理過程

Springboot對注解的處理都發生在AbstractApplicationContext -> refresh() -> invokeBeanFactoryPostProcessors(beanFactory) -> ConfigurationClassPostProcessor -> postProcessBeanDefinitionRegistry()方法中。

(稍微說下也免得我自己忘了, springboot初始化的普通context(非web) 是AnnotationConfigApplicationContext, 在初始化的時候會初始化兩個工具類, AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner 分別用來從 annotation driven 的配置和xml的配置中讀取beanDefinition并向context注冊, 那么在初始化 AnnotatedBeanDefinitionReader 的時候, 會向BeanFactory注冊一個ConfigurationClassPostProcessor 用來處理所有的基于annotation的bean, 這個ConfigurationClassPostProcessor 是 BeanFactoryPostProcessor 的一個實現,springboot會保證在  invokeBeanFactoryPostProcessors(beanFactory) 方法中調用注冊到它上邊的所有的BeanFactoryPostProcessor)

如下代碼顯示是通過 ConfigurationClassParser 類來轉換的

// Parse each @Configuration class    ConfigurationClassParser parser = new ConfigurationClassParser(        this.metadataReaderFactory, this.problemReporter, this.environment,        this.resourceLoader, this.componentScanBeanNameGenerator, registry);

那么在 ConfigurationClassParser -> processConfigurationClass() -> doProcessConfigurationClass() 方法中我們找到了 (這里邊的流程還是很清楚的, 分別按次序處理了@PropertySource, @ComponentScan, @Import, @ImportResource, 在處理這些注解的時候是通過遞歸處理來保證所有的都被處理了)

// Process any @Import annotations    processImports(configClass, sourceClass, getImports(sourceClass), true);

那接下來就看它到底是怎么做的 . 流程依然清晰 :

  首先, 判斷如果被import的是 ImportSelector.class 接口的實現, 那么初始化這個被Import的類, 然后調用它的selectImports方法去獲得所需要的引入的configuration, 然后遞歸處理

  其次, 判斷如果被import的是 ImportBeanDefinitionRegistrar 接口的實現, 那么初始化后將對當前對象的處理委托給這個ImportBeanDefinitionRegistrar (不是特別明白, 只是我的猜測)

  最后, 將import引入的類作為一個正常的類來處理 ( 調用最外層的doProcessConfigurationClass())

所以, 從這里我們知道, 如果你引入的是一個正常的component, 那么會作為@Compoent或者@Configuration來處理, 這樣在BeanFactory里邊可以通過getBean拿到, 但如果你是 ImportSelector 或者 ImportBeanDefinitionRegistrar 接口的實現, 那么spring并不會將他們注冊到beanFactory中,而只是調用他們的方法。

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) {          if (candidate.isAssignable(ImportSelector.class)) {            // Candidate class is an ImportSelector -> delegate to it to determine imports            Class<?> 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 {              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 definitions            Class<?> 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 {            // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->            // process it as an @Configuration class            this.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();      }    }  }

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲欧美国产精品va在线观看| 国产亚洲精品一区二555| 一个色综合导航| 久久精品视频免费播放| 中文亚洲视频在线| 韩剧1988在线观看免费完整版| 丰满岳妇乱一区二区三区| 久久久精品久久久久| 色天天综合狠狠色| 国产深夜精品福利| 久久精品亚洲国产| 丰满岳妇乱一区二区三区| 亚洲成人av资源网| 九九热精品视频国产| 亚洲人成在线观看网站高清| 久精品免费视频| 国产精品久久久久久久一区探花| 最好看的2019年中文视频| 91精品视频大全| 亚洲美女视频网站| 日韩视频在线观看免费| 日韩黄色在线免费观看| 国产性猛交xxxx免费看久久| 欧美电影免费观看高清完整| 国产精品成久久久久三级| 一本大道香蕉久在线播放29| 91精品国产777在线观看| 欧美日韩国产一中文字不卡| 亚洲精品二三区| 欧美一级视频免费在线观看| 亚洲天堂免费观看| 亚洲天堂色网站| 岛国av一区二区三区| 久久影院资源站| 国产精品爽黄69| 国产精品久久久久91| 亚洲视频日韩精品| 国产日本欧美一区二区三区在线| 最近2019中文字幕大全第二页| 亚洲欧美第一页| 中国人与牲禽动交精品| 成人免费看黄网站| 米奇精品一区二区三区在线观看| 亚洲欧美另类中文字幕| 久久久免费电影| 97成人精品视频在线观看| 欧美精品999| 大伊人狠狠躁夜夜躁av一区| 久久这里有精品视频| 亚洲女在线观看| 日韩hd视频在线观看| 国产+成+人+亚洲欧洲| 亚洲精品久久7777777| 亚洲欧洲美洲在线综合| 91网在线免费观看| 精品国产一区二区三区久久| 美女av一区二区| 久久综合免费视频影院| 日本欧美爱爱爱| 麻豆国产精品va在线观看不卡| 亚洲永久在线观看| 日韩有码在线播放| 欧美激情a∨在线视频播放| 青草青草久热精品视频在线观看| 91精品国产自产在线老师啪| 久久久这里只有精品视频| 国产精品自拍视频| 91av视频导航| 国产欧美一区二区三区久久人妖| 亚洲第一精品福利| 26uuu另类亚洲欧美日本老年| 日韩亚洲精品电影| 欧美日韩午夜激情| 激情成人中文字幕| 日韩精品视频免费在线观看| 97久久超碰福利国产精品…| 午夜精品久久久久久久99黑人| 亚洲精品电影网| 欧美成人第一页| 欧美午夜视频在线观看| 欧美国产日韩二区| 色综合久久88色综合天天看泰| 亚洲国产欧美一区| 欧美在线播放视频| 奇米一区二区三区四区久久| 成人妇女免费播放久久久| 久久精品国产96久久久香蕉| 国产精品香蕉av| 精品自拍视频在线观看| 亚洲一区二区三区乱码aⅴ蜜桃女| 精品成人国产在线观看男人呻吟| 久久中文久久字幕| 国产日产欧美精品| 日韩av综合中文字幕| 国产精品久久久久一区二区| 精品成人久久av| 亚洲一区二区日本| 神马久久桃色视频| 国产精品视频精品| 精品成人久久av| 午夜精品一区二区三区在线| 久久久精品国产网站| 福利一区福利二区微拍刺激| 欧美日韩在线视频一区| 欧美日韩在线视频首页| 欧美野外猛男的大粗鳮| 欧美一乱一性一交一视频| 韩国19禁主播vip福利视频| 日韩中文字幕视频| 国产精品一区二区电影| 亚洲色图激情小说| 91亚洲精品一区二区| 欧美与欧洲交xxxx免费观看| 午夜精品在线观看| 久久久国产成人精品| 亚洲www在线| 91高潮精品免费porn| 久久久国产精品免费| 成人国产在线视频| 国产精品第100页| 91精品国产91久久久| 国产精品白丝jk喷水视频一区| 亚洲国产精品人人爽夜夜爽| 日韩中文字幕国产| 亚洲精品久久7777777| 欧美亚洲成人免费| 欧美大片大片在线播放| 日韩av大片免费看| 在线日韩精品视频| 亚洲国产成人精品女人久久久| 国产黑人绿帽在线第一区| 亚洲精品国产免费| 亚洲男人天堂网| 亚洲跨种族黑人xxx| 美女久久久久久久| 亚洲有声小说3d| 色综合五月天导航| 久久久久久九九九| 亚洲欧美制服丝袜| 亚洲激情视频网站| 97在线免费观看| 国产亚洲精品综合一区91| 日韩最新中文字幕电影免费看| 亚洲电影在线看| 亚洲自拍欧美另类| 91精品国产网站| 欧美一级片免费在线| 亚洲欧美精品suv| 日韩视频中文字幕| 欧美午夜精品久久久久久浪潮| 亚洲free性xxxx护士hd| 久久久影视精品| 久久亚洲精品中文字幕冲田杏梨| 午夜精品一区二区三区视频免费看| 麻豆乱码国产一区二区三区| 92裸体在线视频网站| 成人av在线亚洲| 久久久久久久久久久久av| 中文字幕久精品免费视频| 97超视频免费观看| 色妞欧美日韩在线| 国产精品99久久99久久久二8| 亚洲91精品在线观看| 亚洲精品免费网站|