SpringBoot 自动配置启动流程 为什么没有执行selectImports方法

本文详细解析了SpringBoot中自动配置的实现原理,包括@EnableAutoConfiguration的作用、AutoConfigurationImportSelector的工作流程及其如何处理延迟导入选择器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SpringBoot main方法所在类添加了注解@SpringBootApplication, 在此注解中添加了注解@EnableAutoConfiguration, 默认开启了自动配置

@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    ...
}

AutoConfigurationImportSelector实现了DeferredImportSelector接口, 表示为延迟导入, 在Spring容器初始化时, 对此添加了判断, 所以初始化过程中没有执行但是AutoConfigurationImportSelector.selectImports方法
org.springframework.boot.autoconfigure.AutoConfigurationImportSelector

public class AutoConfigurationImportSelector
		implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
		BeanFactoryAware, EnvironmentAware, Ordered {
        ...
}

为什么没有执行org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#selectImports方法

org.springframework.context.annotation.ConfigurationClassParser.processImports

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
    ...
    if (candidate.isAssignable(ImportSelector.class)) {
        // Candidate class is an ImportSelector -> delegate to it to determine imports
        Class<?> candidateClass = candidate.loadClass();
        ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
        ParserStrategyUtils.invokeAwareMethods(
                selector, this.environment, this.resourceLoader, this.registry);
        if (selector instanceof DeferredImportSelector) { // 如果实现了接口DeferredImportSelector 则添加到名为deferredImportSelectors的list中暂存
            this.deferredImportSelectorHandler.handle(
                    configClass, (DeferredImportSelector) selector);
        }
        else { // 否则执行selectImports方法
            String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
            Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
            processImports(configClass, currentSourceClass, importSourceClasses, false);
        }
    }
    ...
}

程序调用栈信息

processImports:565, ConfigurationClassParser (org.springframework.context.annotation)
doProcessConfigurationClass:302, ConfigurationClassParser (org.springframework.context.annotation)
processConfigurationClass:242, ConfigurationClassParser (org.springframework.context.annotation)
parse:199, ConfigurationClassParser (org.springframework.context.annotation)
parse:167, ConfigurationClassParser (org.springframework.context.annotation)
processConfigBeanDefinitions:315, ConfigurationClassPostProcessor (org.springframework.context.annotation)
postProcessBeanDefinitionRegistry:232, ConfigurationClassPostProcessor (org.springframework.context.annotation)
invokeBeanDefinitionRegistryPostProcessors:275, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:95, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:691, AbstractApplicationContext (org.springframework.context.support)
refresh:528, AbstractApplicationContext (org.springframework.context.support)
refresh:142, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
refresh:775, SpringApplication (org.springframework.boot)
refreshContext:397, SpringApplication (org.springframework.boot)
run:316, SpringApplication (org.springframework.boot)
run:1260, SpringApplication (org.springframework.boot)
run:1248, SpringApplication (org.springframework.boot)
main:18, SpringWebApplication (com.cloud.demo)

AutoConfiguration初始化流程

SpringBoot在启动过程中, 会初始化Spring容器, 首要做的就是扫描文件, 创建BeanDefinition对象存储到容器中

程序调用栈

parse:185, ConfigurationClassParser (org.springframework.context.annotation)
processConfigBeanDefinitions:315, ConfigurationClassPostProcessor (org.springframework.context.annotation)
postProcessBeanDefinitionRegistry:232, ConfigurationClassPostProcessor (org.springframework.context.annotation)
invokeBeanDefinitionRegistryPostProcessors:275, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:95, PostProcessorRegistrationDelegate (org.springframework.context.support)
invokeBeanFactoryPostProcessors:691, AbstractApplicationContext (org.springframework.context.support)
refresh:528, AbstractApplicationContext (org.springframework.context.support)
refresh:142, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
refresh:775, SpringApplication (org.springframework.boot)
refreshContext:397, SpringApplication (org.springframework.boot)
run:316, SpringApplication (org.springframework.boot)
run:1260, SpringApplication (org.springframework.boot)
run:1248, SpringApplication (org.springframework.boot)
main:18, SpringWebApplication (com.cloud.demo)

org.springframework.context.annotation.ConfigurationClassParser.parse

public void parse(Set<BeanDefinitionHolder> configCandidates) {
    for (BeanDefinitionHolder holder : configCandidates) {
        BeanDefinition bd = holder.getBeanDefinition();
        try {
            if (bd instanceof AnnotatedBeanDefinition) {
                // 先解析扫描bean, 在此方法中向deferredImportSelectorHandler中添加了一个对象, 存储了可延迟导入的selector列表
                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);
        }
    }
    // 执行对象的process方法
    this.deferredImportSelectorHandler.process();
}

org.springframework.context.annotation.ConfigurationClassParser.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); // 排序 按照优先级、sort大小排序
            deferredImports.forEach(handler::register);
            handler.processGroupImports();
        }
    }
    finally {
        this.deferredImportSelectors = new ArrayList<>();
    }
}

org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGroupingHandler.register

public void register(DeferredImportSelectorHolder deferredImport) {
    // 调用org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.getImportGroup 返回AutoConfigurationGroup.class
    Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
    // 创建Group对象, 用DeferredImportSelectorGrouping包装并存入到map中
    DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
            (group != null ? group : deferredImport),
            key -> new DeferredImportSelectorGrouping(createGroup(group)));
    // 向deferredImports对象添加元素, 后面会使用
    grouping.add(deferredImport);
    // 存入map中 key为启动类的元数据 value是启动类
    this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
            deferredImport.getConfigurationClass());
}

org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGroupingHandler.processGroupImports

public void processGroupImports() {
    for (DeferredImportSelectorGrouping grouping : this.groupings.values()) { // 只有一个元素, 上个方法放入的
        grouping.getImports().forEach(entry -> { // 重点解析
            // 获取主配置类 启动类
            ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
            try {
                // 逐个执行导入 至此执行完成后, 扫描出的类都会注册到BeanDefinition中 等待Spring容器对对象实例化和初始化
                processImports(configurationClass, asSourceClass(configurationClass),
                        asSourceClasses(entry.getImportClassName()), false);
            }
            catch (BeanDefinitionStoreException ex) {
                throw ex;
            }
            catch (Throwable ex) {
                throw new BeanDefinitionStoreException(
                        "Failed to process import candidates for configuration class [" +
                                configurationClass.getMetadata().getClassName() + "]", ex);
            }
        });
    }
}

org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGrouping.getImports

public Iterable<Group.Entry> getImports() {
    // 前面放入的一个元素 此处循环
    for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
        // group为AutoConfigurationGroup对象 执行org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup.process方法
        this.group.process(deferredImport.getConfigurationClass().getMetadata(),
                deferredImport.getImportSelector());
    }
    // 对map结果去重、排序并返回
    return this.group.selectImports();
}

org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.AutoConfigurationGroup.process

public void process(AnnotationMetadata annotationMetadata,
        DeferredImportSelector deferredImportSelector) {
    // 断言
    Assert.state(
            deferredImportSelector instanceof AutoConfigurationImportSelector,
            () -> String.format("Only %s implementations are supported, got %s",
                    AutoConfigurationImportSelector.class.getSimpleName(),
                    deferredImportSelector.getClass().getName()));
    // 调用getAutoConfigurationEntry检索spring.factories文件, 存储并排除文件中配置的bean
    AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
            .getAutoConfigurationEntry(getAutoConfigurationMetadata(),  // 获取了所有包中的spring.factories文件配置参数
                annotationMetadata);

    this.autoConfigurationEntries.add(autoConfigurationEntry);
    for (String importClassName : autoConfigurationEntry.getConfigurations()) {
        // 将过滤后的类存入到entries map中
        this.entries.putIfAbsent(importClassName, annotationMetadata);
    }
}

org.springframework.boot.autoconfigure.AutoConfigurationImportSelector.getAutoConfigurationEntry

protected AutoConfigurationEntry getAutoConfigurationEntry(
        AutoConfigurationMetadata autoConfigurationMetadata,
        AnnotationMetadata annotationMetadata) {
    if (!isEnabled(annotationMetadata)) {
        return EMPTY_ENTRY;
    }
    // 获取EnableAutoConfiguration注解的属性
    AnnotationAttributes attributes = getAttributes(annotationMetadata);
    // 扫描各个包下META-INF/spring.factories文件中配置EnableAutoConfiguration 大约100+
    List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    // Link转Array
    configurations = removeDuplicates(configurations);
    // 获取注解上排除的类  @SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
    Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    checkExcludedClasses(configurations, exclusions);
    // 去掉排除的类
    configurations.removeAll(exclusions);
    // 使用filter过滤 过滤不存在的类(尝试加载 异常说明不存在)
    configurations = filter(configurations, autoConfigurationMetadata);
    // 发送一个AutoConfigurationImportEvent事件通知
    fireAutoConfigurationImportEvents(configurations, exclusions);
    return new AutoConfigurationEntry(configurations, exclusions);
}
<think>嗯,用户让我介绍一下Spring Boot的自动配置启动流程的核心源码理解。首先,我需要确认用户的需求是什么。他们可能正在学习Spring Boot,想要深入了解其内部工作原理,特别是自动配置启动过程。用户可能已经有一些基础,但需要更详细的源码层面的解释,而不仅仅是概念。 接下来,我要考虑从哪里开始。自动配置是Spring Boot的核心特性之一,它基于条件注解来配置Bean。我需要回忆一下相关的核心类,比如@EnableAutoConfiguration,AutoConfigurationImportSelector,以及spring.factories文件的作用。这部分需要解释自动配置是如何被触发和加载的。 然后是启动流程,这部分涉及到SpringApplication类的run方法。用户可能想知道从启动到应用完全运行的过程中,各个阶段都做了什么。比如准备环境、创建应用上下文、加载Bean定义,最后启动Tomcat等嵌入式服务器。需要分解每个步骤,并提到关键的方法,比如refreshContext和onRefresh。 用户可能需要具体的例子或者源码片段来说明这些过程。例如,在自动配置中,如何通过spring.factories加载配置类,条件注解如@ConditionalOnClass是如何起作用的。在启动流程中,SpringApplication.run()中的各个步骤,比如prepareEnvironment、createApplicationContext、refreshContext等。 另外,可能需要提到一些设计模式,比如Spring Boot使用的工厂加载机制(Spring Factories Loader),以及事件驱动模型(Application Events),这些在启动过程中用于处理不同阶段的事件通知。 还需要注意用户的潜在问题,比如自动配置的覆盖和自定义配置的方法,或者启动过程中的扩展点。例如,如何通过排除某些自动配置类,或者使用@SpringBootApplication注解的exclude属性。启动流程中的ApplicationRunner和CommandLineRunner接口,可以在应用启动执行自定义代码。 最后,要确保解释清晰,结构合理,先讲自动配置,再讲启动流程,每个部分分点说明,并给出源码示例或关键类和方法。避免过于深入细节,但又要覆盖主要的核心部分,帮助用户建立整体的理解框架。</think>Spring Boot 的自动配置启动流程是其核心设计理念的体现,以下从源码层面对其核心机制进行拆解: ### 一、自动配置核心源码解析 **1. 触发入口** `@SpringBootApplication` 组合了 `@EnableAutoConfiguration`,其核心逻辑由 `AutoConfigurationImportSelector` 实现。该类通过 `selectImports()` 方法加载配置: ```java // AutoConfigurationImportSelector.java public String[] selectImports(AnnotationMetadata metadata) { List<String> configurations = getCandidateConfigurations(metadata, attributes); configurations = removeDuplicates(configurations); configurations = filter(configurations, autoConfigurationMetadata); return StringUtils.toStringArray(configurations); } ``` **2. 配置加载机制** 通过 `SpringFactoriesLoader` 加载 `META-INF/spring.factories` 文件中的预定义配置类: ```properties # spring-boot-autoconfigure-2.x.jar 中 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\ org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,... ``` **3. 条件化装配** 通过 `@Conditional` 系列注解实现智能装配,典型实现类: ```java // OnClassCondition 检查类路径是否存在目标类 class OnClassCondition extends FilteringSpringBootCondition { // 通过 ClassLoader 加载检查 } ``` **4. 配置优先级控制** 通过 `@AutoConfigureOrder` 和 `@AutoConfigureAfter` 控制配置类加载顺序 --- ### 二、启动流程源码解析 **1. 入口方法** `SpringApplication.run()` 方法核心流程: ```java public ConfigurableApplicationContext run(String... args) { // 1. 初始化监听器 SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); // 2. 准备环境 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); // 3. 创建应用上下文(区分 Web/非Web 环境) context = createApplicationContext(); // 4. 刷新上下文(IoC 容器初始化核心) refreshContext(context); // 5. 执行 Runner 接口实现 callRunners(context, applicationArguments); } ``` **2. 上下文刷新关键** `AbstractApplicationContext.refresh()` 方法包含 12 个标准步骤,核心扩展点: ```java // SpringApplication.java 中的 refreshContext protected void refresh(ApplicationContext applicationContext) { ((AbstractApplicationContext) applicationContext).refresh(); } // 嵌入式容器启动在 onRefresh 阶段 protected void onRefresh() { createWebServer(); // 创建 Tomcat/Jetty 等实例 } ``` **3. 嵌入式容器启动** 以 Tomcat 为例: ```java // TomcatServletWebServerFactory.java public WebServer getWebServer(ServletContextInitializer... initializers) { Tomcat tomcat = new Tomcat(); // 配置 Connector、Context 等组件 return new TomcatWebServer(tomcat); } ``` --- ### 三、关键设计模式 1. **工厂加载机制**:Spring Factories Loader 实现 SPI 扩展 2. **条件判断体系**:基于 ConditionEvaluator 的条件评估框架 3. **事件驱动模型**:通过 ApplicationEvent 实现启动过程状态广播 --- ### 四、调试建议 1. 在 `ConditionEvaluator#shouldSkip` 方法打断点,观察条件判断逻辑 2. 追踪 `ConfigurationClassParser#processConfigurationClass` 查看配置类解析过程 3. 监控 `SpringApplicationRunListeners` 各事件触发节点 理解这些源码需要结合具体场景分析,建议通过实际调试跟踪执行流程,同时参考官方文档中的自动配置报告(`--debug` 模式输出)。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值