Spring中的DeferredImportSelector實(shí)現(xiàn)詳解
前言
在分析DeferredImportSelector之前,根據(jù)名字Deferred(延遲的)ImportSelector。
ImportSelector則是將selectImports返回的字符串?dāng)?shù)組,注冊(cè)成為Bean
那么有幾個(gè)問題:
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í),并沒有分析DeferredImportSelector類型,其兩個(gè)官方的實(shí)現(xiàn)類AutoConfigurationImportSelector和ImportAutoConfigurationImportSelector都是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í)并沒有回調(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的處理過程的時(shí)候并沒有注意到DeferredImportSelector類型的處理過程
按照上面的調(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)之前分析過了,會(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)理解起來比較抽象。在啟動(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)
首先所有的解析過程交給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è)字段,通過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方法,通過Class和反射創(chuàng)建對(duì)象;并且傳入ConfigurationClassParser的environment、resourceLoader、registry對(duì)象,在反射創(chuàng)建完對(duì)象后對(duì)部分Aware方法進(jìn)行了回調(diào)(BeanClassLoaderAware、BeanFactoryAware、EnvironmentAware、ResourceLoaderAware)。
沒搞懂為什么要回調(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ī)還沒有進(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)前需要通過調(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)文章
細(xì)數(shù)java for循環(huán)中的那些坑
這篇文章主要介紹了Java for循環(huán)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-07-07SpringBoot?+?layui?框架實(shí)現(xiàn)一周免登陸功能示例詳解
這篇文章主要介紹了SpringBoot+layui框架實(shí)現(xiàn)一周免登陸功能,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08SpringBoot使用Redis的zset統(tǒng)計(jì)在線用戶信息
這篇文章主要介紹了SpringBoot使用Redis的zset統(tǒng)計(jì)在線用戶信息,幫助大家更好的理解和學(xué)習(xí)使用SpringBoot框架,感興趣的朋友可以了解下2021-04-04Springboot 如何關(guān)閉自動(dòng)配置
這篇文章主要介紹了Springboot 如何關(guān)閉自動(dòng)配置的操作,具有很好的開車價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09spring?retry方法調(diào)用失敗重試機(jī)制示例解析
這篇文章主要為大家介紹了spring?retry方法調(diào)用失敗重試機(jī)制的示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2022-03-03java中對(duì)象轉(zhuǎn)json字符串的三種常用方式
本文主要介紹了java中對(duì)象轉(zhuǎn)json字符串的三種常用方式,包含Jackson庫(kù),Gson庫(kù)和Hutool工具類這三種,具有一定的參考價(jià)值,感興趣的可以了解一下2024-06-06