欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring注解之@Import注解的使用和源碼分析

 更新時(shí)間:2023年04月19日 09:29:58   作者:劉牌  
今天主要介紹Spring @Import注解,在Spring中@Import使用得比較頻繁,它得作用是導(dǎo)入bean,具體的導(dǎo)入方式有多種,特別在SpringBoot項(xiàng)目中,很多地方都使用到了@Import注解,感興趣的小伙伴可以參考閱讀

介紹

今天主要介紹Spring @Import注解,在Spring中@Import使用得比較頻繁,它得作用是導(dǎo)入bean,具體的導(dǎo)入方式有多種,特別在SpringBoot項(xiàng)目中,很多地方都使用到了@Import注解,特別對(duì)于一些和SpringBoot整合的組件,其實(shí)現(xiàn)都大量使用了@Import,例如使用Feign集成SpringBoot時(shí)會(huì)加上注解@EnableFeignClients,使用Dubbo時(shí)會(huì)使用@EnableDubbo等,這些注解里面都使用了@Import注解來(lái)注冊(cè)一些bean。

@Import導(dǎo)入bean的三種方式

@Import導(dǎo)入bean有三種方式,分別是導(dǎo)入普通類,實(shí)現(xiàn)ImportSelector接口的類,實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口的類。

普通類

在開(kāi)放過(guò)程中,盡量保持類不要太過(guò)于龐大,類過(guò)于龐大的話會(huì)變得臃腫復(fù)雜,不好維護(hù),一個(gè)配置類中需要配置很多bean,且邏輯實(shí)現(xiàn)也比較復(fù)雜,代碼量大,如果全部都放在同一個(gè)配置類中,這顯然不太理智,這時(shí)候我們可以將每個(gè)bean單獨(dú)拿出來(lái)放到一個(gè)類里面,然后使用@Import注解導(dǎo)入,如下代碼所示。

  • 定義一個(gè)bean
@Data
public?class?UserBean?{
????private?String?username;
????private?String?sex;
}
  • 導(dǎo)入bean
@Configuration
@Import(value?=?{UserBean.class})??//注入普通Bean
public?class?ImportConfiguration?{

}

從上面可以看出只需要在配置類上面使用@Import注解導(dǎo)入對(duì)應(yīng)Java Bean,然后這個(gè)bean就能注冊(cè)進(jìn)IOC容器中。

ImportSelector接口

ImportSelector是一個(gè)接口,可以通過(guò)實(shí)現(xiàn)它來(lái)完成bean的注冊(cè),它只有一個(gè)selectImports()方法,它會(huì)返回一個(gè)bean的名稱數(shù)組,這個(gè)數(shù)組中的bean名稱就會(huì)被注冊(cè)進(jìn)IOC容器中。

public?class?MyImportSelector?implements?ImportSelector?{
????@Override
????public?String[]?selectImports(AnnotationMetadata?importingClassMetadata)?{
????????return?new?String[]{UserBean.class.getName()};
????}
}

ImportBeanDefinitionRegistrar接口

使用ImportBeanDefinitionRegistrar也可以注冊(cè)bean,它會(huì)傳入BeanDefinitionRegistry接口,然后進(jìn)可以注冊(cè)bean,這里注冊(cè)的是bean的元信息BeanDefinition。

public?class?MyImportBeanDefinitionRegistrar?implements?ImportBeanDefinitionRegistrar?{

????@Override
????public?void?registerBeanDefinitions(AnnotationMetadata?importingClassMetadata,?BeanDefinitionRegistry?registry)?{
????????String?name?=?UserBean.class.getName();
????????BeanDefinitionBuilder?builder?=?BeanDefinitionBuilder.rootBeanDefinition(UserBean.class);
????????builder.addPropertyValue("sex","男");
????????AbstractBeanDefinition?beanDefinition?=?builder.getBeanDefinition();
????????registry.registerBeanDefinition(name,?beanDefinition);
????}
}

源碼解析

spring容器啟動(dòng)后,會(huì)在ConfigurationClassParser解析類中解析@Import注解,解析出需要注冊(cè)的bean,下面就是最關(guān)鍵的代碼,通過(guò)調(diào)用processImports方法,然后解析出對(duì)應(yīng)的bean,可以看出有幾個(gè)判斷,分別判斷是否是ImportSelector類型,ImportBeanDefinitionRegistrar類型,如果都不是,則證明是直接導(dǎo)入普通java類,如果是普通java類和ImportSelector類型,那么就會(huì)將要注冊(cè)的bean加入一個(gè)Map集合configurationClasses中,后續(xù)會(huì)將它進(jìn)行注冊(cè),如果是ImportBeanDefinitionRegistrar類型,那么會(huì)將其加入一個(gè)Map集合importBeanDefinitionRegistrars中,后續(xù)在擴(kuò)展點(diǎn)會(huì)對(duì)它進(jìn)行再次處理。

private?void?processImports(ConfigurationClass?configClass,?ConfigurationClassParser.SourceClass?currentSourceClass,
????????????????????????????????Collection<ConfigurationClassParser.SourceClass>?importCandidates,?Predicate<String>?exclusionFilter,
????????????????????????????????boolean?checkForCircularImports)?{
????????if?(candidate.isAssignable(ImportSelector.class))?{
????????????Class<?>?candidateClass?=?candidate.loadClass();
????????????ImportSelector?selector?=?ParserStrategyUtils.instantiateClass(candidateClass,?ImportSelector.class,
????????????????????this.environment,?this.resourceLoader,?this.registry);
????????????Predicate<String>?selectorFilter?=?selector.getExclusionFilter();
????????????if?(selectorFilter?!=?null)?{
????????????????exclusionFilter?=?exclusionFilter.or(selectorFilter);
????????????}
????????????if?(selector?instanceof?DeferredImportSelector?deferredImportSelector)?{
????????????????this.deferredImportSelectorHandler.handle(configClass,?deferredImportSelector);
????????????}?else?{
????????????????String[]?importClassNames?=?selector.selectImports(currentSourceClass.getMetadata());
????????????????Collection<ConfigurationClassParser.SourceClass>?importSourceClasses?=?asSourceClasses(importClassNames,?exclusionFilter);
????????????????processImports(configClass,?currentSourceClass,?importSourceClasses,?exclusionFilter,?false);
????????????}
????????}?else?if?(candidate.isAssignable(ImportBeanDefinitionRegistrar.class))?{
????????????Class<?>?candidateClass?=?candidate.loadClass();
????????????ImportBeanDefinitionRegistrar?registrar?=
????????????????????ParserStrategyUtils.instantiateClass(candidateClass,?ImportBeanDefinitionRegistrar.class,
????????????????????????????this.environment,?this.resourceLoader,?this.registry);
????????????configClass.addImportBeanDefinitionRegistrar(registrar,?currentSourceClass.getMetadata());
????????}?else?{
????????????this.importStack.registerImport(
????????????????????currentSourceClass.getMetadata(),?candidate.getMetadata().getClassName());
????????????processConfigurationClass(candidate.asConfigClass(configClass),?exclusionFilter);
????????}
????}

經(jīng)過(guò)上面解析后,Spring會(huì)注冊(cè)Bean的元信息,會(huì)通過(guò)configClass.isImported()判斷bean是否是通過(guò)@Import方式導(dǎo)入的普通bean或者ImportSelector類型的導(dǎo)入的bean,如果是,則執(zhí)行registerBeanDefinitionForImportedConfigurationClass,里面主要就是組裝成BeanDefinition,然后注冊(cè)進(jìn)BeanFactory。

private?void?loadBeanDefinitionsForConfigurationClass(ConfigurationClass?configClass,?ConfigurationClassBeanDefinitionReader.TrackedConditionEvaluator?trackedConditionEvaluator)?{
????????if?(trackedConditionEvaluator.shouldSkip(configClass))?{
????????????String?beanName?=?configClass.getBeanName();
????????????if?(StringUtils.hasLength(beanName)?&&?this.registry.containsBeanDefinition(beanName))?{
????????????????this.registry.removeBeanDefinition(beanName);
????????????}
????????????this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
????????????return;
????????}
????????if?(configClass.isImported())?{
????????????registerBeanDefinitionForImportedConfigurationClass(configClass);
????????}
????????for?(BeanMethod?beanMethod?:?configClass.getBeanMethods())?{
????????????loadBeanDefinitionsForBeanMethod(beanMethod);
????????}
????????loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
????????loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
????}

如果是通過(guò)ImportBeanDefinitionRegistrar方式,則會(huì)調(diào)用loadBeanDefinitionsFromRegistrars,里面會(huì)循環(huán)去執(zhí)行我們自定義的ImportBeanDefinitionRegistrar,然后進(jìn)行bean的元信息注冊(cè)。

private?void?loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar,?AnnotationMetadata>?registrars)?{
????registrars.forEach((registrar,?metadata)?->
????????registrar.registerBeanDefinitions(metadata,?this.registry,?this.importBeanNameGenerator));
?}

從上面的源碼解析中,我們看出通過(guò)@Import直接導(dǎo)入普通的java類和導(dǎo)入實(shí)現(xiàn)了ImportSelector接口的類是直接注冊(cè)進(jìn)BeanFactory,這兩者本質(zhì)是一樣的,而通過(guò)實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口方式的類則需要去實(shí)現(xiàn)我們自定義的注冊(cè)bean元信息的邏輯。

總結(jié)

上面我們介紹了@Import的一些場(chǎng)景,@Import用得最多還是一些和Spring結(jié)合的中間件里面,也介紹了它的幾種使用方式,還對(duì)它的源碼進(jìn)行解析,當(dāng)然,只是從它最主要的邏輯去分析,深入的邏輯就沒(méi)去一一詳解,掌握@Import有助于我們?cè)谑褂靡恍┢渌蚣艿臅r(shí)候能夠了解框架的實(shí)現(xiàn)原理,然后更好的去使用框架!

以上就是Spring注解之@Import注解的使用和源碼分析的詳細(xì)內(nèi)容,更多關(guān)于Spring注解@Import的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • IDEA Maven Mybatis generator 自動(dòng)生成代碼(實(shí)例講解)

    IDEA Maven Mybatis generator 自動(dòng)生成代碼(實(shí)例講解)

    下面小編就為大家分享一篇IDEA Maven Mybatis generator 自動(dòng)生成代碼的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • 完整的logback配置示例ELK整合包含生成json日志

    完整的logback配置示例ELK整合包含生成json日志

    這篇文章主要為大家介紹了完整的logback配置示例ELK整合包含生成json日志,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • Java結(jié)合redis實(shí)現(xiàn)接口防重復(fù)提交

    Java結(jié)合redis實(shí)現(xiàn)接口防重復(fù)提交

    本文主要介紹了Java結(jié)合redis實(shí)現(xiàn)接口防重復(fù)提交,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Java迭代器與Collection接口超詳細(xì)講解

    Java迭代器與Collection接口超詳細(xì)講解

    Collection也稱集合,集合概述:集合是Java中提供的一種容器,可以用來(lái)存儲(chǔ)多個(gè)數(shù)據(jù)。Iterator(迭代器)不是一個(gè)集合,它是一種用于訪問(wèn)集合的方法,可用于迭代 ArrayList 和 HashSet 等集合
    2022-07-07
  • Spring Cloud Feign的文件上傳實(shí)現(xiàn)的示例代碼

    Spring Cloud Feign的文件上傳實(shí)現(xiàn)的示例代碼

    這篇文章主要介紹了Spring Cloud Feign的文件上傳實(shí)現(xiàn)的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • Java繪制迷宮動(dòng)畫(huà)并顯示的示例代碼

    Java繪制迷宮動(dòng)畫(huà)并顯示的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用Java語(yǔ)言實(shí)現(xiàn)繪制迷宮動(dòng)畫(huà)并顯示,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Java有一定幫助,需要的可以參考一下
    2022-08-08
  • Java中注解的工作原理

    Java中注解的工作原理

    什么是注解?用一個(gè)詞就可以描述注解,那就是元數(shù)據(jù),即一種描述數(shù)據(jù)的數(shù)據(jù),Java中的注解是如何工作的,需要的朋友可以參考下
    2015-12-12
  • Java中斷一個(gè)線程操作示例

    Java中斷一個(gè)線程操作示例

    這篇文章主要介紹了Java中斷一個(gè)線程操作,結(jié)合實(shí)例形式分析了java中斷線程相關(guān)的interrupt()、isInterrupted()及interrupted()函數(shù)使用技巧,需要的朋友可以參考下
    2019-10-10
  • 使用SpringBoot 配置Oracle和H2雙數(shù)據(jù)源及問(wèn)題

    使用SpringBoot 配置Oracle和H2雙數(shù)據(jù)源及問(wèn)題

    這篇文章主要介紹了使用SpringBoot 配置Oracle和H2雙數(shù)據(jù)源及問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 詳解基于java的Socket聊天程序——客戶端(附demo)

    詳解基于java的Socket聊天程序——客戶端(附demo)

    這篇文章主要介紹了詳解基于java的Socket聊天程序——客戶端(附demo),客戶端設(shè)計(jì)主要分成兩個(gè)部分,分別是socket通訊模塊設(shè)計(jì)和UI相關(guān)設(shè)計(jì)。有興趣的可以了解一下。
    2016-12-12

最新評(píng)論