千家信息网

Spring Boot配置类加载流程示例

发表于:2025-01-24 作者:千家信息网编辑
千家信息网最后更新 2025年01月24日,这篇文章主要讲解了"Spring Boot配置类加载流程示例",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Spring Boot配置类加载流程示例"吧
千家信息网最后更新 2025年01月24日Spring Boot配置类加载流程示例

这篇文章主要讲解了"Spring Boot配置类加载流程示例",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Spring Boot配置类加载流程示例"吧!

本文基于Spring Boot 1.4.1.RELEASE版本

启动代码如下

@SpringBootApplicationpublic 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 configCandidates = new ArrayList();    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() {        @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 configCandidates) {    this.deferredImportSelectors = new LinkedList();    //遍历所有的配置类,根据类型调用不同的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 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 conditions = new ArrayList();    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 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 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 getImports(SourceClass sourceClass) throws IOException {    Set imports = new LinkedHashSet();    Set visited = new LinkedHashSet();    collectImports(sourceClass, imports, visited);    return imports;}//ConfigurationClassParser.java//第461行private void collectImports(SourceClass sourceClass, Set imports, Set 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 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)方法的最后处理(即其他配置类加载完之后)                    if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {                        this.deferredImportSelectors.add(                            new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));                    }                    //普通的ImportSelector接口直接递归处理                    else {                        String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());                        Collection importSourceClasses = asSourceClasses(importClassNames);                        processImports(configClass, currentSourceClass, importSourceClasses, false);                    }                }                //ImportBeanDefinitionRegistrar接口在ConfigurationClassParser.parse(Set)方法执行完毕后处理(即所有配置类加载完之后)                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 readerClass = importResource.getClass("reader");        for (String resource : resources) {            String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);            //xml配置文件跟ImportBeanDefinitionRegistrar接口一样,也会暂存起来            //在ConfigurationClassParser.parse(Set)方法执行完毕后处理(即所有配置类加载完之后)            configClass.addImportedResource(resolvedResource, readerClass);        }    }        //省略部分代码}

6、处理单独的@Bean方法

//ConfigurationClassParser.java//第252行protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {        //省略部分代码        Set beanMethods = sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName());    for (MethodMetadata methodMetadata : beanMethods) {        //暂存起来,在ConfigurationClassParser.parse(Set)方法执行完毕后处理(即所有配置类加载完之后)        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 beanMethods = ifc.getMetadata().getAnnotatedMethods(Bean.class.getName());        for (MethodMetadata methodMetadata : beanMethods) {            if (!methodMetadata.isAbstract()) {                //暂存起来,在ConfigurationClassParser.parse(Set)方法执行完毕后处理(即所有配置类加载完之后)                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 configCandidates) {    //省略部分代码        processDeferredImportSelectors();}//ConfigurationClassParser.java//第473行private void processDeferredImportSelectors() {    List 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 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配置类加载流程示例这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

0