千家信息网

Spring Boot配置类加载流程示例

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,这篇文章主要讲解了"Spring Boot配置类加载流程示例",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Spring Boot配置类加载流程示例"吧
千家信息网最后更新 2026年11月02日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配置类加载流程示例这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

配置 代码 部分 处理 方法 注解 接口 流程 递归 条件 示例 就是 文件 普通 学习 不同 作用 内容 地方 类型 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 百单网互联网科技有限公司怎么样 华服互联网科技怎么样 科技和互联网公司 互联网科技金融公司 科技创新互联网企业 互联网 视角下的科技创新 互联网科技的未来发展 北京三清互联网科技 中盈科技互联网信息有限公司 湖南诚度互联网科技有限公司 互联网科技公司有风险吗 明优互联网科技有限公司 群盈汇互联网科技有限公司 互联网领先科技宣传片 吉林省码上互联网科技电话 互联网科技接地气 科技互联网专业工作会议发言稿 现代互联网科技公司 知域互联网科技有限公司官网 山东亿川互联网科技有限责任公司 齐家互联网科技 卫星互联网科技股票 青岛中康互联网医疗科技有限公司 中国的互联网科技企业的崛起 上海宁丞科技互联网 互联网时代的科技公司 互联网科技融合创新 广州有谷有贝互联网科技有限公司 互联网科技的前景 网互联网络科技
0