中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring Boot配置類加載流程示例

發布時間:2021-06-22 14:40:26 來源:億速云 閱讀:234 作者:chen 欄目:大數據

這篇文章主要講解了“Spring Boot配置類加載流程示例”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Spring Boot配置類加載流程示例”吧!

本文基于Spring Boot 1.4.1.RELEASE版本

啟動代碼如下

@SpringBootApplication
public class SampleApplication {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(SampleApplication.class, args);
    }
}

然后開始分析流程,由于Spring細節眾多,所以我們只關注重點就行了,不然容易迷失在其中

//ConfigurationClassPostProcessor.java
//第273行
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	List<BeanDefinitionHolder> configCandidates = new ArrayList<BeanDefinitionHolder>();
    String[] candidateNames = registry.getBeanDefinitionNames();
	//遍歷已經注冊的所有bean
    for (String beanName : candidateNames) {
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        //判斷這個bean是不是已經被加載過的配置類
        if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
            ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
            }
        }
        //如果沒加載過,判斷一下是不是配置類
        //這個判斷邏輯很簡單,有興趣的朋友可以自己了解一下
        //因為是工具類,其實不看也不影響大局,注意這里check完之后,上邊的校驗就是true了
        else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
        }
    }   
    
    if (configCandidates.isEmpty()) {
        return;
    }
    
    //這段代碼的功能是將配置類按照Order排序,但其實沒有用,
    //因為此時的configCandidates列表中只有一個元素,就是SampleApplication
    Collections.sort(configCandidates, new Comparator<BeanDefinitionHolder>() {
        @Override
        public int compare(BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) {
            int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
            int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
            return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
        }
    });
    
    //省略部分代碼
    
    //這里就是配置解析的關鍵
    parser.parse(candidates);
    
    //省略部分代碼
}

接下來看ConfigurationClassParser這個類

//ConfigurationClassParser.java
//第166行
public void parse(Set<BeanDefinitionHolder> configCandidates) {
    this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();

    //遍歷所有的配置類,根據類型調用不同的parse方法
    //這里分成的三種類型各代表什么,暫時不太清楚
    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);
        }
    }

    //省略部分代碼
}

不同的parse方法會將各種參數組裝成ConfigurationClass對象,傳給processConfigurationClass()

//ConfigurationClassParser.java
//第208行
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    //判斷當前要解析的bean是否符合解析的條件
    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
        return;
    }
    
    ConfigurationClass existingClass = this.configurationClasses.get(configClass);
    if (existingClass != null) {
        if (configClass.isImported()) {
            if (existingClass.isImported()) {
                existingClass.mergeImportedBy(configClass);
            }
            return;
        }
        else {
            this.configurationClasses.remove(configClass);
            for (Iterator<ConfigurationClass> it = this.knownSuperclasses.values().iterator(); it.hasNext(); ) {
                if (configClass.equals(it.next())) {
                    it.remove();
                }
            }
        }
    }
    //省略部分代碼
}

//ConditionEvaluator.java
//第73行
//AnnotatedTypeMetadata:類上的注解信息
//ConfigurationPhase:PARSE_CONFIGURATION-在解析配置時校驗;REGISTER_BEAN-在注冊bean時校驗
public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationPhase phase) {
	//如果沒有配置條件,直接返回
    if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
        return false;
    }

    //如果不指定phase,配置類使用PARSE_CONFIGURATION,其他使用REGISTER_BEAN
    if (phase == null) {
        if (metadata instanceof AnnotationMetadata &&
            ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
            return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
        }
        return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
    }

    //獲取Condition并判斷條件
    List<Condition> conditions = new ArrayList<Condition>();
    for (String[] conditionClasses : getConditionClasses(metadata)) {
        for (String conditionClass : conditionClasses) {
            Condition condition = getCondition(conditionClass, this.context.getClassLoader());
            conditions.add(condition);
        }
    }

    AnnotationAwareOrderComparator.sort(conditions);

    for (Condition condition : conditions) {
        ConfigurationPhase requiredPhase = null;
        if (condition instanceof ConfigurationCondition) {
            requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
        }
        if (requiredPhase == null || requiredPhase == phase) {
            if (!condition.matches(this.context, metadata)) {
                return true;
            }
        }
    }

    return false;
}

開始解析配置類之前,會先判斷當前類是否符合條件以及是否已經解析過,然后才會進入解析流程

//ConfigurationClassParser.java
//第208行
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    
    //省略部分代碼
    
    //遞歸處理配置類和它的父類
    SourceClass sourceClass = asSourceClass(configClass);
    do {
        sourceClass = doProcessConfigurationClass(configClass, sourceClass);
    }
    while (sourceClass != null);

    this.configurationClasses.put(configClass, configClass);
}

解析的流程有點多,我們分段處理

1、處理嵌套(內部)的配置類

//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
    //先遞歸處理嵌套(內部)的配置類
    processMemberClasses(configClass, sourceClass);
    
    //省略部分代碼
}

//ConfigurationClassParser.java
//第326行
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
    for (SourceClass memberClass : sourceClass.getMemberClasses()) {
        if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
            !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
            if (this.importStack.contains(configClass)) {
                this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
            }
            else {
                this.importStack.push(configClass);
                try {
                    //回到最開始解析的地方,遞歸處理
                   processConfigurationClass(memberClass.asConfigClass(configClass));
                }
                finally {
                    this.importStack.pop();
                }
            }
        }
    }
}

2、處理@PropertySource注解

//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
    //省略部分代碼
    
    for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
        sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) {
        if (this.environment instanceof ConfigurableEnvironment) {
            //解析properties配置文件并放到Spring環境中
            processPropertySource(propertySource);
        }
        else {
            logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                        "]. Reason: Environment must implement ConfigurableEnvironment");
        }
    }
    
    //省略部分代碼
}

3、處理@ComponentScan注解

//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
    //省略部分代碼
    
    //獲取所有的@ComponentScan注解
    Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
        sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
    if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
        for (AnnotationAttributes componentScan : componentScans) {
            //根據@ComponentScan注解獲取bean
            Set<BeanDefinitionHolder> scannedBeanDefinitions =
                this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
            
            for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                //判斷掃描的bean中是否有配置類,有的話繼續遞歸解析
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
                    parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
                }
            }
        }
    }
    
    //省略部分代碼
}

4、處理@Import注解,@Import作用是導入Java配置類

Spring Boot的@EnableAutoConfiguration注解也會在這里處理,所以如果你的自動配置類被@ComponentScan注解掃描到了,只會被當做普通的配置類,自動配置排序相關的注解(@AutoConfigureAfter等等)都是無效的

//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
	//省略部分代碼
    
    processImports(configClass, sourceClass, getImports(sourceClass), true);
    
    //省略部分代碼
}

//ConfigurationClassParser.java
//第441行
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
    Set<SourceClass> imports = new LinkedHashSet<SourceClass>();
    Set<SourceClass> visited = new LinkedHashSet<SourceClass>();
    collectImports(sourceClass, imports, visited);
    return imports;
}

//ConfigurationClassParser.java
//第461行
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited) throws IOException {
    //visited保存所有處理過的類,防止重復處理
    if (visited.add(sourceClass)) {
        //取sourceClass上的所有@Import注解,包括其他注解中的@Import注解
        for (SourceClass annotation : sourceClass.getAnnotations()) {
            String annName = annotation.getMetadata().getClassName();
            //這里不太懂為啥判斷java開頭
            if (!annName.startsWith("java") && !annName.equals(Import.class.getName())) {
                collectImports(annotation, imports, visited);
            }
        }
        imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
    }
}

//ConfigurationClassParser.java
//第494行
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {
	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)) {
                    Class<?> candidateClass = candidate.loadClass();
                    ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
                    ParserStrategyUtils.invokeAwareMethods(
                        selector, this.environment, this.resourceLoader, this.registry);
                    //如果是DeferredImportSelector接口,先暫存起來,在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法的最后處理(即其他配置類加載完之后)
                    if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
                        this.deferredImportSelectors.add(
                            new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
                    }
                    //普通的ImportSelector接口直接遞歸處理
                    else {
                        String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                        Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
                        processImports(configClass, currentSourceClass, importSourceClasses, false);
                    }
                }
                //ImportBeanDefinitionRegistrar接口在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法執行完畢后處理(即所有配置類加載完之后)
                else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                    Class<?> candidateClass = candidate.loadClass();
                    ImportBeanDefinitionRegistrar registrar =
                        BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
                    ParserStrategyUtils.invokeAwareMethods(
                        registrar, this.environment, this.resourceLoader, this.registry);
                    configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
                }
                //既不是ImportSelector也不是ImportBeanDefinitionRegistrar,當做普通的@Configuration類處理
                else {
                    this.importStack.registerImport(
                        currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                    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();
        }
    }
}

5、處理@ImportResource注解,@ImportResource作用是導入XML配置

//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
	//省略部分代碼
    
    if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
        AnnotationAttributes importResource =
            AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
        String[] resources = importResource.getStringArray("locations");
        Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
        for (String resource : resources) {
            String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
            //xml配置文件跟ImportBeanDefinitionRegistrar接口一樣,也會暫存起來
            //在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法執行完畢后處理(即所有配置類加載完之后)
            configClass.addImportedResource(resolvedResource, readerClass);
        }
    }
    
    //省略部分代碼
}

6、處理單獨的@Bean方法

//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
	//省略部分代碼
    
    Set<MethodMetadata> beanMethods = sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());
    for (MethodMetadata methodMetadata : beanMethods) {
        //暫存起來,在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法執行完畢后處理(即所有配置類加載完之后)
        configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
    }
    
    //省略部分代碼
}

7、處理實現的接口中的default方法

//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
	//省略部分代碼
    
    processInterfaces(configClass, sourceClass);
    
    //省略部分代碼
}

//ConfigurationClassParser.java
//第349行
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
    for (SourceClass ifc : sourceClass.getInterfaces()) {
        Set<MethodMetadata> beanMethods = ifc.getMetadata().getAnnotatedMethods(Bean.class.getName());
        for (MethodMetadata methodMetadata : beanMethods) {
            if (!methodMetadata.isAbstract()) {
                //暫存起來,在ConfigurationClassParser.parse(Set<BeanDefinitionHolder>)方法執行完畢后處理(即所有配置類加載完之后)
                configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
            }
        }
        //遞歸處理
        processInterfaces(configClass, ifc);
    }
}

8、處理父類中的方法

//ConfigurationClassParser.java
//第252行
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
	//省略部分代碼
    
    if (sourceClass.getMetadata().hasSuperClass()) {
        String superclass = sourceClass.getMetadata().getSuperClassName();
        if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
            this.knownSuperclasses.put(superclass, configClass);
            //如果存在符合條件的父類,返回它,然后繼續解析
            //doProcessConfigurationClass方法被調用的地方是一個while循環,只要不為null就會一直調用
            return sourceClass.getSuperClass();
        }
    }
    
    //省略部分代碼
}

9、處理之前暫存的DeferredImportSelector接口

//ConfigurationClassParser.java
//第166行
public void parse(Set<BeanDefinitionHolder> configCandidates) {
    //省略部分代碼
    
    processDeferredImportSelectors();
}

//ConfigurationClassParser.java
//第473行
private void processDeferredImportSelectors() {
    List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
    this.deferredImportSelectors = null;
    Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);

    for (DeferredImportSelectorHolder deferredImport : deferredImports) {
        ConfigurationClass configClass = deferredImport.getConfigurationClass();
        try {
            String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
            processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
        }
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +
                                                   configClass.getMetadata().getClassName() + "]", ex);
        }
    }
}

10、加載xml配置文件、ImportBeanDefinitionRegistrar接口實現類以及標注了@Bean的方法

//ConfigurationClassPostProcessor.java
//第273行
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    //省略部分代碼
    
    this.reader.loadBeanDefinitions(configClasses);
    
    //省略部分代碼
}

//ConfigurationClassBeanDefinitionReader.java
//第113行
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
    TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
    for (ConfigurationClass configClass : configurationModel) {
        loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
    }
}

//ConfigurationClassBeanDefinitionReader.java
//第124行
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
			TrackedConditionEvaluator trackedConditionEvaluator) {
    //省略部分代碼
    
    if (configClass.isImported()) {
        //將配置類自己也注冊成一個bean
        registerBeanDefinitionForImportedConfigurationClass(configClass);
    }
    for (BeanMethod beanMethod : configClass.getBeanMethods()) {
        //將標記了@Bean的方法加載成bean
        loadBeanDefinitionsForBeanMethod(beanMethod);
    }
    //加載XML配置文件
    loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
    //加載ImportBeanDefinitionRegistrar接口的實現
    loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

感謝各位的閱讀,以上就是“Spring Boot配置類加載流程示例”的內容了,經過本文的學習后,相信大家對Spring Boot配置類加載流程示例這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

山丹县| 同仁县| 肇庆市| 营山县| 黄石市| 孟村| 独山县| 汝南县| 博乐市| 娄底市| 望江县| 水城县| 静乐县| 南丰县| 延安市| 汽车| 鄱阳县| 郴州市| 清远市| 酉阳| 阿克苏市| 苍南县| 苏尼特右旗| 女性| 阿合奇县| 巩留县| 象州县| 吉安县| 建湖县| 朝阳区| 乡城县| 芦溪县| 巴林右旗| 鄯善县| 昌邑市| 武城县| 城固县| 栖霞市| 崇左市| 南投市| 铁岭市|