最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring注解之@Import使用方法講解

 更新時(shí)間:2023年01月03日 09:24:06   作者:程序員小潘  
@Import是Spring基于Java注解配置的主要組成部分,下面這篇文章主要給大家介紹了關(guān)于Spring注解之@Import的簡(jiǎn)單介紹,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下

1. 前言

Spring提供了@Import注解,用于向容器引入我們自定義的類,在許多注解中我們都會(huì)看到它的身影,比如MyBatis在整合Spring時(shí),提供的@MapperScan注解:

@Import(MapperScannerRegistrar.class)
public @interface MapperScan {
}

比如Spring開啟AOP功能的注解:

@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
}

再比如Spring的異步調(diào)用注解:

@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
}

大部分@Enable***注解的原理都差不多,都是通過利用@Import注解向Spring容器注入一些bean來實(shí)現(xiàn)的。

2. 用法

@Import注解可以引入三種類。

1、引入普通類,將作為bean注冊(cè)到Spring容器。

@Configuration
@Import(Person.class)
public class Application {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
        Person person = context.getBean(Person.class);
    }
}

2、引入ImportSelector實(shí)現(xiàn)類,Spring會(huì)將**selectImports()**方法返回的bean數(shù)組注冊(cè)到Spring容器,但是ImportSelector對(duì)象本身不會(huì)注冊(cè)到容器。

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.javap.importt.Person"};
    }
}

3、引入ImportBeanDefinitionRegistrar實(shí)現(xiàn)類,Spring會(huì)暴露 BeanDefinitionRegistry對(duì)象,你可以自由的往容器里面注冊(cè)BeanDefinition,但是ImportBeanDefinitionRegistrar對(duì)象本身不會(huì)注冊(cè)到容器。

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 往registry注冊(cè)BeanDefinition
    }
}

MyBatis整合Spring時(shí),提供的@MapperScan注解引入的就是ImportBeanDefinitionRegistrar的實(shí)現(xiàn)類,MyBatis會(huì)去掃描指定的包路徑,然后將Mapper接口對(duì)應(yīng)的BeanDefinition注冊(cè)到容器里。

3. 源碼分析

解析類上的@Import注解的職責(zé)Spring交給了ConfigurationClassPostProcessor類,它是BeanFactoryPostProcessor的子類,也就是說它屬于BeanFactory的擴(kuò)展點(diǎn)之一,它會(huì)處理容器內(nèi)所有的ConfigurationClass。

ConfigurationClassPostProcessor首先會(huì)過濾出容器內(nèi)所有的ConfigurationClass,然后實(shí)例化一個(gè)ConfigurationClassParser解析器去解析ConfigurationClass,解析過程中就會(huì)處理類上的@Import注解了,方法是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) {
                if (candidate.isAssignable(ImportSelector.class)) {
                    // 引入的是ImportSelector子類
                    Class<?> candidateClass = candidate.loadClass();
                    ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
                    ParserStrategyUtils.invokeAwareMethods(
                            selector, this.environment, this.resourceLoader, this.registry);
                    if (selector instanceof DeferredImportSelector) {
                        this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
                    } else {
                        // 調(diào)用子類方法,得到要引入的beanNames
                        String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                        Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
                        processImports(configClass, currentSourceClass, importSourceClasses, false);
                    }
                } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                    // 引入的是ImportBeanDefinitionRegistrar子類
                    Class<?> candidateClass = candidate.loadClass();
                    // 實(shí)例化子類對(duì)象
                    ImportBeanDefinitionRegistrar registrar =
                            BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
                    ParserStrategyUtils.invokeAwareMethods(
                            registrar, this.environment, this.resourceLoader, this.registry);
                    // 暫存到Map,稍后觸發(fā)
                    configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
                } else {
                    // 引入的是普通類,正常注入到容器
                    this.importStack.registerImport(
                            currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                    // 引入的類可能是ConfigurationClass,遞歸處理
                    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子類,實(shí)例化子類對(duì)象,調(diào)用selectImports()方法得到要注冊(cè)的beanNames,完成注冊(cè)。
  • 如果引入的是ImportBeanDefinitionRegistrar子類,實(shí)例化子類對(duì)象,暫存到Map,稍后觸發(fā)。
  • 如果引入的是普通類,正常注冊(cè)到容器。

對(duì)于ImportBeanDefinitionRegistrar子類,這里只是實(shí)例化了子類對(duì)象然后暫存到Map容器中,此時(shí)還沒有去觸發(fā)ImportBeanDefinitionRegistrar#registerBeanDefinitions()方法。方法的觸發(fā)是在ConfigurationClass解析完以后,ConfigurationClassPostProcessor會(huì)調(diào)用ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromRegistrars()方法遍歷Map容器中所有的ImportBeanDefinitionRegistrar子類對(duì)象,挨個(gè)觸發(fā)擴(kuò)展方法。

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

到此這篇關(guān)于Spring注解之@Import使用方法講解的文章就介紹到這了,更多相關(guān)Spring注解@Import內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺談Java基于Consul創(chuàng)建分布式鎖

    淺談Java基于Consul創(chuàng)建分布式鎖

    這篇文章主要介紹了淺談基于Consul創(chuàng)建分布式鎖,Consul是HashiCorp公司推出的開源工具,用于實(shí)現(xiàn)分布式系統(tǒng)的服務(wù)發(fā)現(xiàn)與配置Consul是分布式的、高可用的、可橫向擴(kuò)展的,需要的朋友可以參考下
    2023-07-07
  • java equals和==的區(qū)別詳解

    java equals和==的區(qū)別詳解

    這篇文章主要介紹了java equals和==的區(qū)別詳解的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • Java線程生命周期圖文詳細(xì)講解

    Java線程生命周期圖文詳細(xì)講解

    在java中,任何對(duì)象都要有生命周期,線程也不例外,它也有自己的生命周期。線程的整個(gè)生命周期可以分為5個(gè)階段,分別是新建狀態(tài)、就緒狀態(tài)、運(yùn)行狀態(tài)、阻塞狀態(tài)和死亡狀態(tài)
    2023-01-01
  • JAVA寶藏工具h(yuǎn)utool的使用

    JAVA寶藏工具h(yuǎn)utool的使用

    開發(fā)過程中總是會(huì)遇到需要自己自定義工具類的情況,做一些數(shù)據(jù)轉(zhuǎn)換、字符串操作、日期處理、加解密、編解碼、金額計(jì)算等,本文就詳細(xì)的介紹有一個(gè)工具類hutool的使用,感興趣的可以了解一下
    2021-10-10
  • Java 生成PDF文檔的示例代碼

    Java 生成PDF文檔的示例代碼

    這篇文章主要介紹了Java 生成PDF文檔的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-08-08
  • java多線程Future和Callable類示例分享

    java多線程Future和Callable類示例分享

    JAVA多線程實(shí)現(xiàn)方式主要有三種:繼承Thread類、實(shí)現(xiàn)Runnable接口、使用ExecutorService、Callable、Future實(shí)現(xiàn)有返回結(jié)果的多線程。其中前兩種方式線程執(zhí)行完后都沒有返回值,只有最后一種是帶返回值的。今天我們就來研究下Future和Callable的實(shí)現(xiàn)方法
    2016-01-01
  • 解決grails服務(wù)端口沖突的辦法(grails修改端口號(hào))

    解決grails服務(wù)端口沖突的辦法(grails修改端口號(hào))

    grails中默認(rèn)的服務(wù)端口為8080,當(dāng)本機(jī)中需要同時(shí)啟動(dòng)兩個(gè)不同的項(xiàng)目時(shí),就會(huì)造成端口沖突,下面給出解決方法
    2013-12-12
  • 快速排序算法原理及java遞歸實(shí)現(xiàn)

    快速排序算法原理及java遞歸實(shí)現(xiàn)

    快速排序 對(duì)冒泡排序的一種改進(jìn),若初始記錄序列按關(guān)鍵字有序或基本有序,蛻化為冒泡排序。使用的是遞歸原理,在所有同數(shù)量級(jí)O(n longn) 的排序方法中,其平均性能最好。就平均時(shí)間而言,是目前被認(rèn)為最好的一種內(nèi)部排序方法
    2014-01-01
  • 大數(shù)據(jù) java hive udf函數(shù)的示例代碼(手機(jī)號(hào)碼脫敏)

    大數(shù)據(jù) java hive udf函數(shù)的示例代碼(手機(jī)號(hào)碼脫敏)

    這篇文章主要介紹了大數(shù)據(jù) java hive udf函數(shù)(手機(jī)號(hào)碼脫敏),的相關(guān)知識(shí),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • SpringBoot使用minio進(jìn)行文件管理的流程步驟

    SpringBoot使用minio進(jìn)行文件管理的流程步驟

    MinIO 是一個(gè)高性能的對(duì)象存儲(chǔ)系統(tǒng),兼容 Amazon S3 API,該軟件設(shè)計(jì)用于處理非結(jié)構(gòu)化數(shù)據(jù),如圖片、視頻、日志文件以及備份數(shù)據(jù)等,本文給大家介紹了SpringBoot使用minio進(jìn)行文件管理的流程步驟,需要的朋友可以參考下
    2025-01-01

最新評(píng)論

衢州市| 福建省| 富裕县| 大港区| 黔西县| 麻城市| 绥化市| 垦利县| 巧家县| 西和县| 连城县| 玉环县| 岳普湖县| 札达县| 庄河市| 竹山县| 金溪县| 东源县| 神木县| 峨边| 进贤县| 诏安县| 龙岩市| 嘉黎县| 桂平市| 望城县| 兰溪市| 芮城县| 奎屯市| 左云县| 海淀区| 松潘县| 海阳市| 镇巴县| 洪湖市| 昔阳县| 阳曲县| 固原市| 禹州市| 玉树县| 卫辉市|