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

Spring中的DeferredImportSelector實(shí)現(xiàn)詳解

 更新時(shí)間:2024年01月03日 09:15:46   作者:it_lihongmin  
這篇文章主要介紹了Spring中的DeferredImportSelector實(shí)現(xiàn)詳解,兩個(gè)官方的實(shí)現(xiàn)類AutoConfigurationImportSelector和ImportAutoConfigurationImportSelector都是Spring Boot后新增的實(shí)現(xiàn),需要的朋友可以參考下

前言

在分析DeferredImportSelector之前,根據(jù)名字Deferred(延遲的)ImportSelector。

ImportSelector則是將selectImports返回的字符串?dāng)?shù)組,注冊(cè)成為Bean

那么有幾個(gè)問(wèn)題:

1)、怎么延遲的;

2)、執(zhí)行時(shí)機(jī),或者在什莫時(shí)候被調(diào)用的;

3)、返回后的字符串?dāng)?shù)組,怎么注冊(cè)成Bean(或者Beandefinition)。

一、DeferredImportSelector類結(jié)構(gòu)和接口調(diào)用時(shí)機(jī)

之前在分析Spring源碼時(shí),并沒(méi)有分析DeferredImportSelector類型,其兩個(gè)官方的實(shí)現(xiàn)類AutoConfigurationImportSelectorImportAutoConfigurationImportSelector都是Spring Boot后新增的實(shí)現(xiàn)。

public interface DeferredImportSelector extends ImportSelector {
    default Class<? extends Group> getImportGroup() {
        return null;
    }
    interface Group {
        void process(AnnotationMetadata metadata, DeferredImportSelector selector);
        Iterable<Entry> selectImports();
        class Entry {
            private final AnnotationMetadata metadata;
            private final String importClassName;
            public Entry(AnnotationMetadata metadata, String importClassName) {
                this.metadata = metadata;
                this.importClassName = importClassName;
            }
        }
    }
}

DeferredImportSelector的回調(diào)時(shí)機(jī)發(fā)生在ConfigurationClassPostProcessor處理階段,但是在處理DeferredImportSelector類型時(shí)并沒(méi)有回調(diào)從頂層接口ImportSelector的selectImports(AnnotationMetadata importingClassMetadata)方法,則按道理AutoConfigurationImportSelector(自動(dòng)裝配)的該接口只需要寫一個(gè)空方法即可。

執(zhí)行該回調(diào)方法的先后順序?yàn)?Group#process 和 Group#selectImports,回調(diào)時(shí)機(jī)為:

AbstractApplicationContext #refresh

AbstractApplicationContext #invokeBeanFactoryPostProcessors

PostProcessorRegistrationDelegate #invokeBeanFactoryPostProcessors

PostProcessorRegistrationDelegate #invokeBeanDefinitionRegistryPostProcessors

ConfigurationClassPostProcessor #postProcessBeanDefinitionRegistry

ConfigurationClassPostProcessor #processConfigBeanDefinitions

ConfigurationClassParser #parse

ConfigurationClassParser$DeferredImportSelectorHandler #process (下面都為代理對(duì)象處理)

ConfigurationClassParser$DeferredImportSelectorGroupingHandler #processGroupImports

ConfigurationClassParser$DeferredImportSelectorGrouping #getImports

之前在分析ConfigurationClassPostProcessor的處理過(guò)程的時(shí)候并沒(méi)有注意到DeferredImportSelector類型的處理過(guò)程

按照上面的調(diào)用trace繼續(xù)分析,ConfigurationClassParser #parse方法,如下:

public void parse(Set<BeanDefinitionHolder> configCandidates) {
    for (BeanDefinitionHolder holder : configCandidates) {
        BeanDefinition bd = holder.getBeanDefinition();
        try {
            if (bd instanceof AnnotatedBeanDefinition) {
                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);
        }
    }
 
    this.deferredImportSelectorHandler.process();
}

其中for循環(huán)之前分析過(guò)了,會(huì)將可能存在的Bean進(jìn)行注入,并且繼續(xù)進(jìn)行解析肯能的注解情況,比如:有一個(gè)@Component標(biāo)注的類,上面還有@Import等情況。而deferredImportSelectorHandler.process()則是對(duì)DeferredImportSelector類型的處理。

看一下DeferredImportSelectorHandler deferredImportSelectorHandler的結(jié)構(gòu):

private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();

唯一的屬性就是存放DeferredImportSelector類型的List,還有handle和process兩個(gè)方法。而DeferredImportSelectorHolder的結(jié)構(gòu)為:

private static class DeferredImportSelectorHolder {
    // 注解所在類
    private final ConfigurationClass configurationClass;
    // DeferredImportSelector類型,比如:AutoConfigurationImportSelector
    private final DeferredImportSelector importSelector;
}

DeferredImportSelector的兩個(gè)官方實(shí)現(xiàn)都是Spring Boot的,看到上面的結(jié)構(gòu)理解起來(lái)比較抽象。在啟動(dòng)Spring Boot項(xiàng)目時(shí),默認(rèn)只會(huì)注入一對(duì)值:

configurationClass為被@SpringBootApplication標(biāo)注的啟動(dòng)類;

DeferredImportSelector為AutoConfigurationImportSelector類型。

二、DeferredImportSelectorHandler的process方法

繼續(xù)deferredImportSelectorHandler.process()分析:

public void process() {    List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;    this.deferredImportSelectors = null;    try {        if (deferredImports != null) {            DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();            deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);            deferredImports.forEach(handler::register);            handler.processGroupImports();        }    } finally {        this.deferredImportSelectors = new ArrayList<>();    }}

1)、創(chuàng)建DeferredImportSelectorGroupingHandler對(duì)象,對(duì)DeferredImportSelectorHolder類型List進(jìn)行排序,然后遍歷調(diào)用DeferredImportSelectorGroupingHandler的register方法,將DeferredImportSelectorHolder數(shù)據(jù)set到DeferredImportSelectorGroupingHandler內(nèi)。

2)、調(diào)用hander的processGroupImports方法進(jìn)行解析注冊(cè)。

3)、finally,將容器置為空。

1、DeferredImportSelectorGroupingHandler結(jié)構(gòu)

首先所有的解析過(guò)程交給DeferredImportSelectorGroupingHandler進(jìn)行處理,先看看其內(nèi)部結(jié)構(gòu)。

private class DeferredImportSelectorGroupingHandler {
 
    private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
 
    private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();
}

有兩個(gè)字段,通過(guò)register方法挨個(gè)進(jìn)行register(相當(dāng)于set方法)到上兩個(gè)字段中, 最后統(tǒng)一調(diào)用processGroupImports方法進(jìn)行處理。

1)、configurationClasses比較清楚,存放的是注解信息和標(biāo)記注解的類(比如:當(dāng)前為@SpringBootApplication鎖在的類的注解信息被封裝為StrandardAnnotationMetadata)。

2)、group中存儲(chǔ)的key為DeferredImportSelector.Group或者DeferredImportSelectorHolder對(duì)象(因?yàn)槭钦{(diào)用DeferredImportSelector的getImportGroup方法獲取的,可能為null,所以key為Object類型)。value為DeferredImportSelectorGrouping類型,再看看其結(jié)構(gòu)(還是比較清晰的,只是需要理解幾層的關(guān)系):

private static class DeferredImportSelectorGrouping {
 
    private final DeferredImportSelector.Group group;
 
    private final List<DeferredImportSelectorHolder> deferredImports = new ArrayList<>();
}

2、DeferredImportSelectorGroupingHandler的register方法

public void register(DeferredImportSelectorHolder deferredImport) {
    Class<? extends Group> group = deferredImport.getImportSelector()
            .getImportGroup();
    DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
            (group != null ? group : deferredImport),
            key -> new DeferredImportSelectorGrouping(createGroup(group)));
    grouping.add(deferredImport);
    this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
            deferredImport.getConfigurationClass());
}

1)、調(diào)用DeferredImportSelector.Group的getImportGroup方法,獲取返回的DeferredImportSelector.Group。

2)、grouping的put方法,Group為null則設(shè)置傳入的DeferredImportSelectorHolder 本身。value為new的DeferredImportSelectorHolder 類型。

調(diào)用了createGroup方法,通過(guò)Class和反射創(chuàng)建對(duì)象;并且傳入ConfigurationClassParser的environment、resourceLoader、registry對(duì)象,在反射創(chuàng)建完對(duì)象后對(duì)部分Aware方法進(jìn)行了回調(diào)(BeanClassLoaderAware、BeanFactoryAware、EnvironmentAware、ResourceLoaderAware)。

沒(méi)搞懂為什么要回調(diào),因?yàn)锽ean的生命周期本身就會(huì)進(jìn)行回調(diào)。后面debugger發(fā)現(xiàn),AutoConfigurationImportSelector本身實(shí)現(xiàn)了那幾個(gè)接口,AutoConfigurationImportSelector.AutoConfigurationGroup也實(shí)現(xiàn)了那幾個(gè)接口。知道當(dāng)前的調(diào)用時(shí)機(jī)還沒(méi)有進(jìn)行g(shù)etBean操作,不能執(zhí)行生命周期方法(回調(diào),設(shè)置BeanFactory等),但是執(zhí)行DeferredImportSelector的process和selectImports方法時(shí)可能需要使用到上面四個(gè)AbstractApplicationContext級(jí)別的內(nèi)置對(duì)象,則在此處回調(diào)賦值。

3)、上面先進(jìn)行了put方法,返回了DeferredImportSelectorGrouping對(duì)象。再將DeferredImportSelectorHolder添加進(jìn)去。

4)、為L(zhǎng)ist<DeferredImportSelectorHolder> deferredImports 添加值。

3、DeferredImportSelectorGroupingHandler的processGroupImports方法

public void processGroupImports() {
    for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
        grouping.getImports().forEach(entry -> {
            ConfigurationClass configurationClass = this.configurationClasses.get(
                    entry.getMetadata());
            try {
                processImports(configurationClass, asSourceClass(configurationClass),
                        asSourceClasses(entry.getImportClassName()), false);
            } catch (BeanDefinitionStoreException ex) {
                // 省略異常代碼
            }
        });
    }
}

主要有兩步

1)、調(diào)用getImports方法獲取Iterable<Group.Entry>

public Iterable<Group.Entry> getImports() {
    for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
        this.group.process(deferredImport.getConfigurationClass().getMetadata(),
                deferredImport.getImportSelector());
    }
    return this.group.selectImports();
}

之前做了很多準(zhǔn)備工作,當(dāng)前需要通過(guò)調(diào)用DeferredImportSelector.Group的process和selectImports方法,返回Iterable<DeferredImportSelector.Group.Entry> 類型對(duì)象,后續(xù)調(diào)用統(tǒng)一的processImports方法進(jìn)行處理。

2)、遍歷調(diào)用ConfigurationClassParser的processImports方法,將返回的Class類型進(jìn)行解析并注冊(cè)成Bean(如果該Class上有其他注解,也會(huì)遞歸進(jìn)行解析注冊(cè)完成,比如該類上還有@ComponentScan注解)。

到此這篇關(guān)于Spring中的DeferredImportSelector實(shí)現(xiàn)詳解的文章就介紹到這了,更多相關(guān)DeferredImportSelector實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot詳細(xì)講解多個(gè)配置文件的配置流程

    SpringBoot詳細(xì)講解多個(gè)配置文件的配置流程

    SpringBoot項(xiàng)目是一個(gè)標(biāo)準(zhǔn)的Maven項(xiàng)目,它的配置文件需要放在src/main/resources/下,其文件名必須為application,其存在兩種文件形式,分別是properties和yaml(或者yml)文件
    2022-06-06
  • Java枚舉類型enum的詳解及使用

    Java枚舉類型enum的詳解及使用

    這篇文章主要介紹了Java枚舉類型enum的詳解及使用的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • 關(guān)于CommandLineRunner的使用詳解

    關(guān)于CommandLineRunner的使用詳解

    本文介紹了如何在SpringBoot項(xiàng)目啟動(dòng)時(shí)使用CommandLineRunner和ApplicationRunner接口進(jìn)行數(shù)據(jù)預(yù)加載或操作,通過(guò)實(shí)現(xiàn)這兩個(gè)接口,可以在項(xiàng)目啟動(dòng)時(shí)執(zhí)行特定的任務(wù),同時(shí),還展示了如何使用@Order注解來(lái)控制多個(gè)實(shí)現(xiàn)類的加載順序
    2024-12-12
  • Java try()語(yǔ)句實(shí)現(xiàn)try-with-resources異常管理機(jī)制操作

    Java try()語(yǔ)句實(shí)現(xiàn)try-with-resources異常管理機(jī)制操作

    這篇文章主要介紹了Java try()語(yǔ)句實(shí)現(xiàn)try-with-resources異常管理機(jī)制操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • java 多線程實(shí)現(xiàn)在線咨詢(udp)

    java 多線程實(shí)現(xiàn)在線咨詢(udp)

    這篇文章主要介紹了java 多線程實(shí)現(xiàn)在線咨詢(udp)的示例,幫助大家更好的理解和學(xué)習(xí)Java 網(wǎng)絡(luò)編程的相關(guān)內(nèi)容,感興趣的朋友可以了解下
    2020-11-11
  • spring boot結(jié)合Redis實(shí)現(xiàn)工具類的方法示例

    spring boot結(jié)合Redis實(shí)現(xiàn)工具類的方法示例

    這篇文章主要介紹了spring boot結(jié)合Redis實(shí)現(xiàn)工具類的方法示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-11-11
  • 實(shí)例詳解SpringBoot默認(rèn)的JSON解析方案

    實(shí)例詳解SpringBoot默認(rèn)的JSON解析方案

    JSON數(shù)據(jù)現(xiàn)在是我們開發(fā)中用的最多的,百分之九十的數(shù)據(jù)都是通過(guò)JSON方式進(jìn)行傳輸,下面這篇文章主要給大家介紹了關(guān)于SpringBoot默認(rèn)的JSON解析方案的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • Mybatis實(shí)現(xiàn)SQL映射的兩種方法(xml文件形式和注解形式)

    Mybatis實(shí)現(xiàn)SQL映射的兩種方法(xml文件形式和注解形式)

    這篇文章主要介紹了Mybatis實(shí)現(xiàn)SQL映射的兩種方法(xml文件形式和注解形式),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • java識(shí)別一篇文章中某單詞出現(xiàn)個(gè)數(shù)的方法

    java識(shí)別一篇文章中某單詞出現(xiàn)個(gè)數(shù)的方法

    這篇文章主要介紹了java識(shí)別一篇文章中某單詞出現(xiàn)個(gè)數(shù)的方法,涉及java字符解析操作的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-10-10
  • Spring注入bean的四種方式總結(jié)

    Spring注入bean的四種方式總結(jié)

    我們談到Spring的時(shí)候一定會(huì)提到IOC容器、DI依賴注入,Spring通過(guò)將一個(gè)個(gè)類標(biāo)注為Bean的方法注入到IOC容器中,達(dá)到了控制反轉(zhuǎn)的效果,Spring幫我們實(shí)現(xiàn)了一種通過(guò)注解來(lái)實(shí)現(xiàn)注入的方法,所以本文為大家介紹了Spring注入bean的四種方式,需要的朋友可以參考下
    2025-11-11

最新評(píng)論

丹阳市| 雷山县| 桑日县| 甘肃省| 同江市| 呈贡县| 城市| 成安县| 建湖县| 舒城县| 阳江市| 贵南县| 竹北市| 建平县| 东宁县| 宝鸡市| 洛隆县| 武夷山市| 永川市| 平顶山市| 广安市| 廉江市| 灵璧县| 高清| 沅江市| 淮北市| 翁牛特旗| 灵璧县| 三台县| 将乐县| 澄城县| 汶上县| 西宁市| 虞城县| 安泽县| 吴忠市| 彩票| 宁河县| 亳州市| 确山县| 阿鲁科尔沁旗|