springboot @EnableAutoConfiguration自動(dòng)配置超詳解

springboot相關(guān)邏輯

1. main啟動(dòng)類

首先就是springboot項(xiàng)目習(xí)以為常的main方法調(diào)用SpringApplication.run將標(biāo)注有@SpringBootApplication注解的class對(duì)象作為參數(shù)傳遞。SpringBootApplication注解是個(gè)組合注解,主要組合了@Configuration@EnableAutoConfiguration,@Import(AutoConfigurationImportSelector.class)@ComponentScan等關(guān)鍵注解司训。

@SpringBootApplication
public class SampleWebUiApplication {
    public static void main(String[] args) {
        SpringApplication.run(SampleWebUiApplication.class, args);
    }
}
2. 調(diào)用SpringApplication構(gòu)造函數(shù)

通過第一步調(diào)用靜態(tài)方法run,內(nèi)部轉(zhuǎn)換為實(shí)例化SpringApplication并調(diào)用實(shí)例方法run。

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        /**
         * 通過getSpringFactoriesInstances 方法從META-INF/spring.factories文件中獲取所有ApplicationContextInitializer 回調(diào)接口踪少,
         * 用于在刷新之前初始化Spring ConfigurableApplicationContext。
         * 通常在需要對(duì)應(yīng)用程序上下文進(jìn)行一些編程初始化的Web應(yīng)用程序中使用糠涛。
         * 例如援奢,注冊(cè)屬性源或針對(duì)上下文環(huán)境激活配置文件。
         * 有關(guān)分別聲明“ contextInitializerClasses”上下文參數(shù)和初始化參數(shù)的信息忍捡,請(qǐng)參見ContextLoader和FrameworkServlet支持集漾。
         * 鼓勵(lì)A(yù)pplicationContextInitializer處理器檢測(cè)是否已實(shí)現(xiàn)Spring的Ordered接口,或者是否存在@Order注釋砸脊,并在調(diào)用之前對(duì)實(shí)例進(jìn)行相應(yīng)的排序具篇。
         */
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
    }

SpringApplication#getSpringFactoriesInstances 從"META-INF/spring.factories"中加載并實(shí)例化給定類型的所有實(shí)現(xiàn)類

ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
// 使用給定的類加載器從“META-INF/spring.factories”中加載給定類型的所有實(shí)現(xiàn)類全限定名。
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 通過反射實(shí)例化所有從上面獲取的全限定類名
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
3. 調(diào)用SpringApplication實(shí)例對(duì)象的run方法

SpringApplication#run

...... 忽略部分代碼
try {
    ... 
    // 1. 通過反射實(shí)例化ApplicationContext
    // 2. 實(shí)例化applicationContext時(shí)調(diào)用其無參構(gòu)造函數(shù)實(shí)例化AnnotatedBeanDefinitionReader凌埂,ClassPathBeanDefinitionScanner
    // 3. 實(shí)例化AnnotatedBeanDefinitionReader時(shí)構(gòu)造函數(shù)通過AnnotationConfigUtils.registerAnnotationConfigProcessors注冊(cè)一些內(nèi)部必要的BeanDefinition
    // 如 ConfigurationClassPostProcessor(處理@Configuration @Import等注解), AutowiredAnnotationBeanPostProcessor(自動(dòng)注入)等驱显。
    context = createApplicationContext();
    exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
        new Class[]{ConfigurableApplicationContext.class}, context);
    // 1. 調(diào)用從spring.factories加載的
    // 2. 加載primarySources以及sources到BeanDefinition(用于解析@SpringBootApplication,通過ConfigurationClassPostProcessor)
    prepareContext(context, environment, listeners, applicationArguments, printedBanner);
    // 1. 調(diào)用AbstractApplicationContext#refresh方法
    // 2. 通過調(diào)用invokeBeanFactoryPostProcessors方法調(diào)用ConfigurationClassPostProcessor處理primarySources類的注解
    // 3. ConfigurationClassPostProcessor處理@SpringBootApplication的元注解@ComponentScan掃描包組件注冊(cè)到BeanDefinitionRegistry
    // 4. ConfigurationClassPostProcessor通過@EnableAutoConfiguration的元注解@Import中的AutoConfigurationImportSelector自動(dòng)導(dǎo)入spring.factories中的類到BeanDefinitionRegistry
    // 5.啟動(dòng)內(nèi)置web容器(調(diào)用ServletWebServerApplicationContext#onRefresh)
    refreshContext(context);
    afterRefresh(context, applicationArguments);
            ... 
    } catch (Throwable ex) {
        ...
    }
    try {
        listeners.running(context);
    } catch (Throwable ex) {
            ...
    }
    return context;

SpringApplication#createApplicationContext 用于創(chuàng)建ApplicationContext的策略方法,默認(rèn)情況下,此方法將使用任何明確設(shè)置的應(yīng)用程序上下文或應(yīng)用程序上下文類,然后再使用合適的默認(rèn)值埃疫。

Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
    try {
        switch (this.webApplicationType) {
            case SERVLET:
                //org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
                contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                break;
            case REACTIVE:
                // org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext
                contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                break;
            default:
                // org.springframework.context.annotation.AnnotationConfigApplicationContext
                contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
            }
     } catch (ClassNotFoundException ex) {
            throw new IllegalStateException(
        "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
     }
}  
// 通過反射實(shí)例化context,在對(duì)應(yīng)ApplicationContext的構(gòu)造方法中實(shí)例化{@link AnnotatedBeanDefinitionReader
// 并在該reader的構(gòu)造方法中通過{@link AnnotationConfigUtils#registerAnnotationConfigProcessors}
// 注冊(cè)一些內(nèi)部必要的BeanDefinition如:{@link ConfigurationClassPostProcessor},{@link AutowiredAnnotationBeanPostProcessor}等
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);

上訴方法最后一步反射實(shí)例化應(yīng)用上下文時(shí)伏恐,很關(guān)鍵的一步就是向容器中注冊(cè)一些非常重要的的BeanDefinition(如:ConfigurationClassPostProcessorAutowiredAnnotationBeanPostProcessor等)栓霜,主要步驟:AnnotationConfigServletWebServerApplicationContext() -> new AnnotatedBeanDefinitionReader -> AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)

AnnotationConfigUtils.registerAnnotationConfigProcessors 注冊(cè)spring內(nèi)部必要的一些beanDefinition

···      
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    // 在Spring#refresh時(shí)調(diào)用invokeBeanFactoryPostProcessors(beanFactory)方法時(shí)調(diào)用翠桦,用來處理@Configuration @Import等注解
    RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
    def.setSource(source);
    // CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME = "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"
    beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
...

下圖斷點(diǎn)為createApplicationContext方法執(zhí)行結(jié)束后,beanDefinitionMap中的內(nèi)容

createApplicationContext執(zhí)行結(jié)束后beanDefinitionMap值

SpringApplication#prepareContext 準(zhǔn)備上下文

...
// 調(diào)用從spring.factories獲取的ApplicationContextInitializer
applyInitializers(context);
 ...
// 獲取所有資源胳蛮,如在main方法中傳進(jìn)來的SampleWebUiApplication.class等
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 將資源注冊(cè)為BeanDefinition
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);

下圖斷點(diǎn)為prepareContext方法執(zhí)行結(jié)束后销凑,beanDefinitionMap中的內(nèi)容

prepareContext執(zhí)行結(jié)束后beanDefinitionMap值

SpringApplication#refreshContext 刷新上下文具體如下。

spring refresh之invokeBeanFactoryPostProcessors

調(diào)用ConfigurationClassPostProcessor整體流程圖

AbstractApplicationContext#refresh

......
// 調(diào)用實(shí)現(xiàn)BeanFactoryPostProcessor的后置處理器仅炊,
// 其實(shí)就是在上述new AnnotatedBeanDefinitionReader時(shí)注冊(cè)的解析配置類的后置處理器ConfigurationClassPostProcessor
// 這里主要解析SpringBootApplication元注解中的Import注解以及ComponentScan注解等斗幼。
invokeBeanFactoryPostProcessors(beanFactory);
......

AbstractApplicationContext#invokeBeanFactoryPostProcessors

//由于之前注冊(cè)的都是BeanDefinition,此時(shí)還并沒有生產(chǎn)任何的BeanFactoryPostProcessor,所以getBeanFactoryPostProcessors是空的
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors 從beanDefinitionMap中獲取實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor接口的實(shí)現(xiàn)類茂洒,并調(diào)用

//放置已處理的beanName
Set<String> processedBeans = new HashSet<>();
//放置常規(guī)的后置處理器孟岛,就是只實(shí)現(xiàn)了BeanFactoryPostProcessor接口的
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
//放置實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessor接口的,之前我們注冊(cè)的后置處理器中只有ConfigurationClassPostProcessor實(shí)現(xiàn)了
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
//放置當(dāng)前的RegistryProcessors
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
//查找實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessor接口的BeanName,其實(shí)目前就只有一個(gè)ConfigurationClassPostProcessor
String[] postProcessorNames =
    beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
    //ConfigurationClassPostProcessor同樣實(shí)現(xiàn)了PriorityOrdered接口
    if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
        //調(diào)用了getBean方法督勺,產(chǎn)生了ConfigurationClassPostProcessor實(shí)例,放到currentRegistryProcessors集合中
        currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
        processedBeans.add(ppName);
    }
}
//排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
//將實(shí)例化出來的后置處理器放到集合中
registryProcessors.addAll(currentRegistryProcessors);
// 調(diào)用ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

//清空渠羞,以便處理后面的后置處理器
currentRegistryProcessors.clear();
//再次查找實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessor接口的BeanName,這里就是可能就是從配置類中解析出來的一些
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
    //不包括已經(jīng)處理過的智哀,并且先處理實(shí)現(xiàn)Ordered接口的
    if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
        currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
        processedBeans.add(ppName);
    }
}
//根據(jù)Ordered排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
//將后置處理器放到已注冊(cè)的集合中
registryProcessors.addAll(currentRegistryProcessors);
//調(diào)用所有后置處理器的postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//再次清理次询,因?yàn)楹竺孢€要處理未實(shí)現(xiàn)Ordered接口的
currentRegistryProcessors.clear();
......

ConfigurationClassPostProcessor#processConfigBeanDefinitions 處理@Configuration注解以及相關(guān)的@Bean,@Import等注解

    //放置候選配置類
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    String[] candidateNames = registry.getBeanDefinitionNames();
    //遍歷之前注冊(cè)的所有bean定義,找到其中的配置類瓷叫,其實(shí)就是我們自己傳進(jìn)來的配置類
    for (String beanName : candidateNames) {
        //...省略校驗(yàn)過程...
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        //檢查是否是有@Configuration注解的BeanDifinition -> full類型的配置類 -> 會(huì)把配置類替換成動(dòng)態(tài)代理類
        //或者該類包含@Component @ComponentScan @Import @ImportResource @Bean 注解的其中之一 -> lite類型的配置類  -> 不會(huì)替換成動(dòng)態(tài)代理類
        else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
        }
    }
    //....省略片段....
    //實(shí)例化一個(gè)配置類解析器
    ConfigurationClassParser parser = new ConfigurationClassParser(
        this.metadataReaderFactory, this.problemReporter, this.environment,
        this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    
    do {
        //解析配置類
        parser.parse(candidates);
        parser.validate();
        //parser.getConfigurationClasses()就是拿到剛剛解析完放到map中的配置類
        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
        configClasses.removeAll(alreadyParsed);
        
        //這里處理@Import導(dǎo)入的beanDefintion和配置類中的@Bean
        this.reader.loadBeanDefinitions(configClasses);
        alreadyParsed.addAll(configClasses);
        //以下邏輯是找出未解析的配置類屯吊,如@Bean和ImportBeanDefinitionRegistrar所引入的
        candidates.clear();
        if (registry.getBeanDefinitionCount() > candidateNames.length) {
            String[] newCandidateNames = registry.getBeanDefinitionNames();
            Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
            Set<String> alreadyParsedClasses = new HashSet<>();
            for (ConfigurationClass configurationClass : alreadyParsed) {
                alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
            }
            for (String candidateName : newCandidateNames) {
                if (!oldCandidateNames.contains(candidateName)) {
                    BeanDefinition bd = registry.getBeanDefinition(candidateName);
                    //將是配置類并且沒有解析過的BeanDefinition放到候選集合中繼續(xù)解析
                    if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                        !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                        candidates.add(new BeanDefinitionHolder(bd, candidateName));
                    }
                }
            }
            candidateNames = newCandidateNames;
        }
    }
    while (!candidates.isEmpty());

ConfigurationClassUtils.checkConfigurationClassCandidate 檢查給定的bean定義是否是配置類(或在配置類/組件類中聲明的嵌套類,也要自動(dòng)注冊(cè))摹菠,并進(jìn)行相應(yīng)標(biāo)記盒卸。

...
//檢查是否有標(biāo)識(shí)@Configuration
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
    //設(shè)置配置屬性值為full
    beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
//檢查是否包含@Component @ComponentScan @Import @ImportResource @Bean
else if (config != null || isConfigurationCandidate(metadata)) {
    //設(shè)置配置屬性值為lite
    beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
    return false;
}

經(jīng)過checkConfigurationClassCandidate后,此時(shí)容器中只有啟動(dòng)類屬于配置類次氨,進(jìn)行解析的只有該類蔽介,當(dāng)然后續(xù)還有解析出來的其他配置類會(huì)在while里繼續(xù)解析

第一次需要解析的配置類

ConfigurationClassParser#parse 配置類解析流程

for (BeanDefinitionHolder holder : configCandidates) {
        BeanDefinition bd = holder.getBeanDefinition();
        // 配置類的beanDefinition為AnnotatedGenericBeanDefinition
        if (bd instanceof AnnotatedBeanDefinition) {
            //傳入配置類的元數(shù)據(jù)與beanName
            parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
        }
    ......
}
// 處理實(shí)現(xiàn)了DeferredImportSelector接口的實(shí)現(xiàn)類,用來延遲處理@Import
// @EnableAutoConfiguration注解導(dǎo)入的AutoConfigurationImportSelector就屬于該類型
this.deferredImportSelectorHandler.process()

protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
    processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}

ConfigurationClassParser#processConfigurationClass


...
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
        //解析配置類煮寡,這里可能返回配置類的父類虹蓄,需要繼續(xù)處理
     sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
//將配置類放入map中
this.configurationClasses.put(configClass, configClass);

ConfigurationClassParser#doProcessConfigurationClass

......
//@Configuration 本身也是 @Component的組合注解
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
    // 處理內(nèi)置類,如果內(nèi)置類也是個(gè)配置類幸撕,遞歸處理內(nèi)置類
    processMemberClasses(configClass, sourceClass, filter);
}

// Process any @ComponentScan annotations
// 找出配置類上的@ComponentScan注解屬性
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
    sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);

for (AnnotationAttributes componentScan : componentScans) {
    //將@ComponentScan引入的所有類掃描成BeanDefinition并注冊(cè)到容器中
    Set<BeanDefinitionHolder> scannedBeanDefinitions =
        this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
    //這里循環(huán)是為了判斷掃描出來的beanDefinition是否是配置類薇组,如果是配置類的話需要遞歸解析
    for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
        BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
        //這里是必然為true, 能被掃描出來的必然有@Component注解,而@Component注解為lite配置類
        //這里主要是為了在檢查的同時(shí)設(shè)置一下full或者lite的類型
        if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
            //配置類就繼續(xù)遞歸解析
            parse(bdCand.getBeanClassName(), holder.getBeanName());
        }
    }
}
// 處理@Import注解
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
...
// 將配置類中@Bean的方法解析成方法元數(shù)據(jù)放到配置類中
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
    configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
...

ConfigurationClassParser#processImports 處理@Import注解

//importCandidates為@Import中的value數(shù)組
    for (SourceClass candidate : importCandidates) {
        if (candidate.isAssignable(ImportSelector.class)) {
            // Candidate class is an ImportSelector -> delegate to it to determine imports
            Class<?> candidateClass = candidate.loadClass();
            //實(shí)例化我們寫的實(shí)現(xiàn)ImportSelector接口的類
            ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
                                                                           this.environment, this.resourceLoader, this.registry);

            if (selector instanceof DeferredImportSelector) {
                // 如果是實(shí)現(xiàn)了延遲導(dǎo)入坐儿,則用延遲導(dǎo)入方式導(dǎo)入
               // 將其加入到deferredImportSelectors數(shù)組中律胀,待全部處理完后在ConfigurationClassParser#parse方法最后進(jìn)行處理導(dǎo)入
                // @EnableAutoConfiguration注解導(dǎo)入的AutoConfigurationImportSelector就屬于該類型
                this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
            } else {
                //調(diào)用selectImports方法返回我們需要注入到容器中bean數(shù)組
                String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                //轉(zhuǎn)為SourceClass集合
                Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
                //再次遞歸調(diào)用本方法宋光,如果我們返回的數(shù)組是一些沒有實(shí)現(xiàn)Import相關(guān)接口的類,
                //就會(huì)走到最后的else邏輯炭菌,當(dāng)成配置類處理
                processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
            }               
        }
        //這里就走實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口的邏輯
        else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
            // Candidate class is an ImportBeanDefinitionRegistrar ->
            // delegate to it to register additional bean definitions
            Class<?> candidateClass = candidate.loadClass();
            //實(shí)例化
            ImportBeanDefinitionRegistrar registrar =
                ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
                                                     this.environment, this.resourceLoader, this.registry);
            //這里先把Registrar放到配置類的importBeanDefinitionRegistrars屬性中跃须,最后解析完調(diào)用loadBeanDefinition進(jìn)行處理
            configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
        }
        else {
            //普通的bean當(dāng)做配置類處理
            processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
        }
    }

處理完上述方法后回到ConfigurationClassParser#parse的最后一步處理DeferredImportSelector接口實(shí)現(xiàn)類(this.deferredImportSelectorHandler.process()),調(diào)用ConfigurationClassParser.DeferredImportSelectorGroupingHandler#processGroupImports

此時(shí)只有該延遲處理的導(dǎo)入類

ConfigurationClassParser.DeferredImportSelectorGrouping#getImports 獲取DeferredImportSelector導(dǎo)入的條目

for (DeferredImportSelectorHolder deferredImport : this.deferredImports {
  // 調(diào)用AutoConfigurationImportSelector.AutoConfigurationGroup#process獲取需要自動(dòng)導(dǎo)入的配置類
 this.group.process(deferredImport.getConfigurationClass().getMetadata(),
            deferredImport.getImportSelector());
}
return this.group.selectImports();

AutoConfigurationImportSelector.AutoConfigurationGroup#process 獲取需要自動(dòng)導(dǎo)入的配置類信息

// 從META-INFO/spring.factories文件下獲取EnableAutoConfiguration對(duì)應(yīng)的配置類列表
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
                    .getAutoConfigurationEntry(annotationMetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
    this.entries.putIfAbsent(importClassName, annotationMetadata);
}

AutoConfigurationImportSelector#getAutoConfigurationEntry

...
// 從META-INFO/spring.factories文件下獲取EnableAutoConfiguration對(duì)應(yīng)的配置類列表
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    // 從META-INFO/spring.factories文件下獲取org.springframework.boot.autoconfigure.EnableAutoConfiguration對(duì)應(yīng)的配置類列表
    // getSpringFactoriesLoaderFactoryClass() -> EnableAutoConfiguration.class
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "+ "are using a custom packaging, make sure that file is correct.");
    return configurations;
}

執(zhí)行完getCandidateConfigurations獲取到的配置列表

getCandidateConfigurations獲取到的配置類列表

最后回到ConfigurationClassPostProcessor#processConfigBeanDefinitions方法中的的this.reader.loadBeanDefinitions(configClasses)將解析出來的類注冊(cè)到beanDefinitionMap娃兽,之后在refresh的finishBeanFactoryInitialization方法中實(shí)例化這些bean。

加載后beanDefinitionMap中的值
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末尽楔,一起剝皮案震驚了整個(gè)濱河市投储,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌阔馋,老刑警劉巖玛荞,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異呕寝,居然都是意外死亡勋眯,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門下梢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來客蹋,“玉大人,你說我怎么就攤上這事孽江⊙扰鳎” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵岗屏,是天一觀的道長(zhǎng)辆琅。 經(jīng)常有香客問我,道長(zhǎng)这刷,這世上最難降的妖魔是什么婉烟? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮暇屋,結(jié)果婚禮上似袁,老公的妹妹穿的比我還像新娘。我一直安慰自己率碾,他們只是感情好叔营,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著所宰,像睡著了一般绒尊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上仔粥,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天婴谱,我揣著相機(jī)與錄音蟹但,去河邊找鬼。 笑死谭羔,一個(gè)胖子當(dāng)著我的面吹牛华糖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播瘟裸,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼客叉,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了话告?” 一聲冷哼從身側(cè)響起兼搏,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎沙郭,沒想到半個(gè)月后佛呻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡病线,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年吓著,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片送挑。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绑莺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惕耕,到底是詐尸還是另有隱情紊撕,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布赡突,位于F島的核電站对扶,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏惭缰。R本人自食惡果不足惜浪南,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望漱受。 院中可真熱鬧络凿,春花似錦、人聲如沸昂羡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)虐先。三九已至怨愤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蛹批,已是汗流浹背撰洗。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工篮愉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人差导。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓试躏,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親设褐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子颠蕴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容