Spring Boot 自动配置的完整启动流程

1 阅读5分钟

好的,这是 Spring Boot 最核心的机制,面试中属于必考深度题。我会从启动入口到自动配置加载,完整拆解整个流程。


Spring Boot 启动全流程

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

这行代码背后发生了7个关键阶段


阶段一:构造 SpringApplication(实例化)

// SpringApplication.run() 内部
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return new SpringApplication(primarySource).run(args);  // 先构造,再运行
}

构造过程(推断应用类型 + 加载初始化器):

步骤操作关键代码
1. 推断应用类型检查类路径判断是 Servlet/Reactive/NoneWebApplicationType.deduceFromClasspath()
2. 加载 BootstrapRegistryInitializerspring.factories 加载getSpringFactoriesInstances()
3. 加载 ApplicationContextInitializer上下文初始化器同上
4. 加载 ApplicationListener应用事件监听器同上
5. 推断主类通过堆栈分析找到包含 main 方法的类deduceMainApplicationClass()

推断应用类型的逻辑

static WebApplicationType deduceFromClasspath() {
    if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", null)
            && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", null)) {
        return WebApplicationType.REACTIVE;  // WebFlux
    }
    for (String className : SERVLET_INDICATOR_CLASSES) {  // Servlet 相关类
        if (!ClassUtils.isPresent(className, null)) {
            return WebApplicationType.NONE;  // 非 Web
        }
    }
    return WebApplicationType.SERVLET;  // Spring MVC(默认)
}

阶段二:运行 SpringApplication(run 方法核心)

public ConfigurableApplicationContext run(String... args) {
    // 1. 启动计时器
    StartupStep startupStep = this.applicationStartup.start("spring.boot.application.starting");
    
    // 2. 创建 DefaultBootstrapContext(引导上下文)
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    
    ConfigurableApplicationContext context = null;
    
    // 3. 配置 Headless 模式(无显示器环境)
    configureHeadlessProperty();
    
    // 4. 发布启动事件(监听器可以在此介入)
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting(bootstrapContext, this.mainApplicationClass);
    
    try {
        // 5. 封装命令行参数
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        
        // 6. 【关键】准备 Environment(加载配置文件)
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
        
        // 7. 打印 Banner
        Banner printedBanner = printBanner(environment);
        
        // 8. 【关键】创建 ApplicationContext(根据类型创建)
        context = createApplicationContext();
        context.setApplicationStartup(this.applicationStartup);
        
        // 9. 【核心】准备 Context(加载自动配置在此!)
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
        
        // 10. 【核心】刷新 Context(Bean 定义加载 + 实例化)
        refreshContext(context);
        
        // 11. 后置处理
        afterRefresh(context, applicationArguments);
        
        startupStep.end();
        listeners.started(context);
        
        // 12. 执行 Runner(ApplicationRunner / CommandLineRunner)
        callRunners(context, applicationArguments);
        
    } catch (Throwable ex) {
        handleRunFailure(context, ex, listeners);
        throw new IllegalStateException(ex);
    }
    
    listeners.running(context);
    return context;
}

阶段三:准备 Environment(配置加载)

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
        DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
    
    // 1. 创建或获取 Environment(StandardServletEnvironment)
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    
    // 2. 配置 PropertySources 和 Profiles
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    
    // 3. 【关键】发布环境准备事件,ConfigFileApplicationListener 响应
    //    这里加载 application.yml / application-{profile}.yml
    listeners.environmentPrepared(bootstrapContext, environment);
    
    return environment;
}

ConfigFileApplicationListener 的加载逻辑

// 加载顺序(低优先级 → 高优先级,高覆盖低)
1. jar 外部的 application-{profile}.properties/yml
2. jar 内部的 application-{profile}.properties/yml  
3. jar 外部的 application.properties/yml
4. jar 内部的 application.properties/yml

阶段四:创建 ApplicationContext

protected ConfigurableApplicationContext createApplicationContext() {
    return this.applicationContextFactory.apply(this.webApplicationType);
}

// 根据类型创建不同上下文
switch (webApplicationType) {
    case SERVLET:
        // AnnotationConfigServletWebServerApplicationContext
        return new ServletWebServerApplicationContext();
    case REACTIVE:
        // AnnotationConfigReactiveWebServerApplicationContext  
        return new ReactiveWebServerApplicationContext();
    default:
        // AnnotationConfigApplicationContext
        return new ApplicationContext();
}

阶段五:准备 Context(【核心】自动配置入口)

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
        ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments, Banner printedBanner) {
    
    // 1. 设置 Environment
    context.setEnvironment(environment);
    
    // 2. 后置处理 Context(注册 beanNameGenerator、resourceLoader 等)
    postProcessApplicationContext(context);
    
    // 3. 【关键】执行 ApplicationContextInitializer
    applyInitializers(context);
    
    // 4. 发布 ContextPrepared 事件
    listeners.contextPrepared(context);
    
    // 5. 注册 Spring Boot 特殊 Bean
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    if (printedBanner != null) {
        beanFactory.registerSingleton("springBootBanner", printedBanner);
    }
    
    // 6. 【核心】加载主类(@SpringBootApplication 所在类)
    Set<Object> sources = getAllSources();
    load(context, sources.toArray(new Object[0]));  // 注册为 BeanDefinition
    
    // 7. 发布 ContextLoaded 事件
    listeners.contextLoaded(context);
}

阶段六:刷新 Context(【核心】自动配置加载)

refreshContext()AbstractApplicationContext.refresh()

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 1. 准备刷新(设置启动时间、状态等)
        prepareRefresh();
        
        // 2. 获取 BeanFactory(DefaultListableBeanFactory)
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        
        // 3. 准备 BeanFactory(注册类加载器、表达式解析器等)
        prepareBeanFactory(beanFactory);
        
        try {
            // 4. 子类扩展(ServletContext 相关处理)
            postProcessBeanFactory(beanFactory);
            
            // 5. 【关键】执行 BeanFactoryPostProcessor
            //    ConfigurationClassPostProcessor 在这里处理 @Configuration 类
            invokeBeanFactoryPostProcessors(beanFactory);
            
            // 6. 注册 BeanPostProcessor
            registerBeanPostProcessors(beanFactory);
            
            // 7. 初始化 MessageSource
            initMessageSource();
            
            // 8. 初始化 ApplicationEventMulticaster
            initApplicationEventMulticaster();
            
            // 9. 子类扩展(创建 WebServer,如 Tomcat)
            onRefresh();
            
            // 10. 注册监听器
            registerListeners();
            
            // 11. 【关键】实例化所有非懒加载的单例 Bean
            finishBeanFactoryInitialization(beanFactory);
            
            // 12. 完成刷新(发布 ContextRefreshedEvent)
            finishRefresh();
        }
        // ...
    }
}

6.1 核心:invokeBeanFactoryPostProcessors

// ConfigurationClassPostProcessor 处理 @Configuration 类
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 解析 @Configuration 类,包括 @ComponentScan、@Import、@Bean 等
    processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}

解析主类的 @SpringBootApplication

@SpringBootApplication  // 组合注解
public class Application { }

// 等价于:
@Configuration
@EnableAutoConfiguration      // 【核心】开启自动配置
@ComponentScan                // 组件扫描
public class Application { }

阶段七:@EnableAutoConfiguration 原理

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage      // 将主类所在包注册为自动配置包
@Import(AutoConfigurationImportSelector.class)  // 【核心】导入自动配置类
public @interface EnableAutoConfiguration {}

7.1 AutoConfigurationImportSelector 加载流程

public class AutoConfigurationImportSelector implements 
        DeferredImportSelector, BeanClassLoaderAware, ... {
    
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // 1. 检查是否启用自动配置(spring.boot.enableautoconfiguration)
        if (!isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        }
        
        // 2. 从 META-INF/spring-autoconfigure-metadata.properties 加载元数据
        AutoConfigurationMetadata autoConfigurationMetadata = 
            AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
        
        // 3. 【关键】获取候选自动配置类
        List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
        
        // 4. 去重
        configurations = removeDuplicates(configurations);
        
        // 5. 获取需要排除的类(@EnableAutoConfiguration(exclude=...))
        Set<String> exclusions = getExclusions(annotationMetadata, attributes);
        
        // 6. 检查排除类合法性
        checkExcludedClasses(configurations, exclusions);
        configurations.removeAll(exclusions);
        
        // 7. 【关键】按条件过滤(@Conditional 评估)
        configurations = getConfigurationClassFilter().filter(configurations);
        
        // 8. 发布自动配置导入事件
        fireAutoConfigurationImportEvents(configurations, exclusions);
        
        return StringUtils.toStringArray(configurations);
    }
}

7.2 获取候选配置类(SPI 机制)

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, 
        AnnotationAttributes attributes) {
    // 从 META-INF/spring.factories 加载
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
        getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
    
    Assert.notEmpty(configurations, 
        "No auto configuration classes found in META-INF/spring.factories");
    
    return configurations;
}

// spring.factories 示例(Spring Boot 2.7+ 改为 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
...(约 100+ 个)

7.3 条件过滤(@Conditional 生效)

private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
    long startTime = System.nanoTime();
    String[] candidates = StringUtils.toStringArray(configurations);
    boolean[] skip = new boolean[candidates.length];
    boolean skipped = false;
    
    // 获取所有条件过滤器(OnClassCondition, OnBeanCondition, OnPropertyCondition 等)
    for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
        invokeAwareMethods(filter);
        
        // 批量匹配条件(优化性能,避免每个类单独检查)
        boolean[] match = filter.match(candidates, autoConfigurationMetadata);
        
        for (int i = 0; i < match.length; i++) {
            if (!match[i]) {
                skip[i] = true;
                candidates[i] = null;  // 标记为跳过
                skipped = true;
            }
        }
    }
    
    // 收集通过的类
    if (!skipped) {
        return configurations;
    }
    List<String> result = new ArrayList<>(candidates.length);
    for (int i = 0; i < candidates.length; i++) {
        if (!skip[i]) {
            result.add(candidates[i]);
        }
    }
    return result;
}

完整流程图

┌─────────────────────────────────────────────────────────────────┐
│                    SpringApplication.run()                        │
├─────────────────────────────────────────────────────────────────┤
│  1. 构造 SpringApplication                                       │
│     ├── 推断 Web 类型 (Servlet/Reactive/None)                    │
│     ├── 加载 spring.factories: BootstrapRegistryInitializer      │
│     ├── 加载 spring.factories: ApplicationContextInitializer     │
│     └── 加载 spring.factories: ApplicationListener               │
├─────────────────────────────────────────────────────────────────┤
│  2. 运行 run()                                                   │
│     ├── 发布 Starting 事件                                       │
│     ├── 准备 Environment(加载 application.yml)                 │
│     ├── 打印 Banner                                              │
│     ├── 创建 ApplicationContext                                  │
│     ├── 准备 Context                                             │
│     │   ├── 执行 ApplicationContextInitializer                   │
│     │   ├── 加载主类(@SpringBootApplication)                   │
│     │   └── 发布 ContextPrepared/ContextLoaded 事件              │
│     ├── 【核心】刷新 Context                                      │
│     │   ├── invokeBeanFactoryPostProcessors                      │
│     │   │   └── ConfigurationClassPostProcessor                  │
│     │   │       └── 解析 @Configuration                          │
│     │   │           ├── 处理 @ComponentScan(包扫描)             │
│     │   │           ├── 处理 @Import(导入配置类)                 │
│     │   │           │   └── @EnableAutoConfiguration            │
│     │   │           │       └── AutoConfigurationImportSelector   │
│     │   │           │           ├── 读取 spring.factories         │
│     │   │           │           ├── 获取 100+ 自动配置类            │
│     │   │           │           ├── @Conditional 过滤            │
│     │   │           │           │   ├── OnClassCondition         │
│     │   │           │           │   ├── OnBeanCondition          │
│     │   │           │           │   └── OnPropertyCondition      │
│     │   │           │           └── 注册通过的 BeanDefinition     │
│     │   │           └── 处理 @Bean 方法                          │
│     │   ├── 注册 BeanPostProcessor                               │
│     │   ├── onRefresh()(创建 WebServer,如 Tomcat)              │
│     │   ├── finishBeanFactoryInitialization(实例化单例 Bean)     │
│     │   └── finishRefresh()                                      │
│     ├── 执行 ApplicationRunner / CommandLineRunner               │
│     └── 发布 Running 事件                                        │
└─────────────────────────────────────────────────────────────────┘

关键优化点(面试加分项)

优化说明版本
spring-autoconfigure-metadata.properties编译期生成条件元数据,避免运行时反射检查类是否存在2.0+
DeferredImportSelector延迟导入,确保用户配置优先于自动配置1.5+
批量条件评估一次检查多个类,减少 ClassLoader 查询次数2.0+
AOT 处理(Spring Boot 3+)原生镜像支持,启动时无需反射扫描3.0+

面试回答模板

"Spring Boot 启动流程分为构造和运行两个阶段。构造阶段推断应用类型、加载初始化器;运行阶段先准备 Environment 加载配置文件,然后创建 ApplicationContext。核心是 refresh 过程,其中 ConfigurationClassPostProcessor 解析主类的 @SpringBootApplication,触发 @EnableAutoConfiguration,通过 AutoConfigurationImportSelector 从 spring.factories 读取自动配置类,再经过 @Conditional 条件过滤,最终注册符合条件的 BeanDefinition 到容器。"