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

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

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

1. 前言

Spring提供了@Import注解,用于向容器引入我們自定義的類,在許多注解中我們都會看到它的身影,比如MyBatis在整合Spring時,提供的@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來實現(xiàn)的。

2. 用法

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

1、引入普通類,將作為bean注冊到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實現(xiàn)類,Spring會將**selectImports()**方法返回的bean數(shù)組注冊到Spring容器,但是ImportSelector對象本身不會注冊到容器。

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

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

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

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

3. 源碼分析

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

ConfigurationClassPostProcessor首先會過濾出容器內(nèi)所有的ConfigurationClass,然后實例化一個ConfigurationClassParser解析器去解析ConfigurationClass,解析過程中就會處理類上的@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();
                    // 實例化子類對象
                    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子類,實例化子類對象,調(diào)用selectImports()方法得到要注冊的beanNames,完成注冊。
  • 如果引入的是ImportBeanDefinitionRegistrar子類,實例化子類對象,暫存到Map,稍后觸發(fā)。
  • 如果引入的是普通類,正常注冊到容器。

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

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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解Spring Cloud Gateway修改請求和響應(yīng)body的內(nèi)容

    詳解Spring Cloud Gateway修改請求和響應(yīng)body的內(nèi)容

    這篇文章主要介紹了Spring Cloud Gateway修改請求和響應(yīng)body的內(nèi)容的相關(guān)資料,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • Mybatis的核心架構(gòu)及源碼解讀

    Mybatis的核心架構(gòu)及源碼解讀

    這篇文章主要介紹了Mybatis的核心架構(gòu)及源碼解讀,mybatis是一款半自動化的持久層框架,它封裝了JDBC操作,支持定制化SQL,高級映射,但它的數(shù)據(jù)庫無關(guān)性較低,需要的朋友可以參考下
    2023-08-08
  • Java的垃圾回收機制實例分析

    Java的垃圾回收機制實例分析

    這篇文章主要介紹了Java的垃圾回收機制,結(jié)合實例形式分析了垃圾回收機制的原理及相關(guān)操作技巧,需要的朋友可以參考下
    2019-08-08
  • 一文詳解Spring事務(wù)的實現(xiàn)與本質(zhì)

    一文詳解Spring事務(wù)的實現(xiàn)與本質(zhì)

    這篇文章主要介紹了Spring中事務(wù)的兩種實現(xiàn)方式:聲明式事務(wù)、編程式事務(wù)以及他們的本質(zhì)。文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-04-04
  • Spring如何利用@Value注解讀取yml中的map配置

    Spring如何利用@Value注解讀取yml中的map配置

    這篇文章主要介紹了Spring如何利用@Value注解讀取yml中的map配置,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • 如何使用Java在excel單元格中設(shè)置超鏈接

    如何使用Java在excel單元格中設(shè)置超鏈接

    這篇文章主要介紹了如何使用Java在excel單元格中設(shè)置超鏈接,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11
  • SpringBoot整合JPA方法及配置解析

    SpringBoot整合JPA方法及配置解析

    這篇文章主要介紹了SpringBoot整合JPA方法及配置過程,JPA是Java Persistence API的簡稱,中文名Java持久層API,感興趣想要詳細了解可以參考下文
    2023-05-05
  • Maven修改運行環(huán)境配置代碼實例

    Maven修改運行環(huán)境配置代碼實例

    這篇文章主要介紹了Maven修改運行環(huán)境配置代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-04-04
  • 詳解Spring Security 中的四種權(quán)限控制方式

    詳解Spring Security 中的四種權(quán)限控制方式

    這篇文章主要介紹了詳解Spring Security 中的四種權(quán)限控制方式,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • java IO 字節(jié)流詳解及實例代碼

    java IO 字節(jié)流詳解及實例代碼

    這篇文章主要介紹了java IO 字節(jié)流詳解及實例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-03-03

最新評論