Skip to content

Spring Boot 启动流程深度解析

目录

  1. 概述
  2. 入口方法 SpringApplication.run()
  3. SpringApplication 构造函数初始化
  4. run() 方法核心流程
  5. 启动器监听器 (ApplicationListener)
  6. 环境准备 (Environment Preparation)
  7. 配置数据加载机制 (ConfigData Loading)
  8. ApplicationContext 创建与初始化
  9. 自动配置 (Auto-Configuration)
  10. 上下文刷新 (Context Refresh)
  11. Bean 生命周期
  12. Web 容器启动
  13. 启动完成回调
  14. 应用事件生命周期
  15. 优雅关闭 (Graceful Shutdown)
  16. 一句话总结

概述

Spring Boot 的启动流程是一个精心设计的多阶段过程,从 JVM 启动到应用程序完全就绪,涉及多个关键组件的协同工作。整个流程以 SpringApplication 类为核心,通过一系列有序的步骤完成应用的引导(Bootstrap)。

核心组件

组件职责
SpringApplication启动流程的核心入口,协调所有启动步骤
SpringApplicationRunListeners管理启动过程中的事件监听器
ConfigurableEnvironment管理应用的环境配置和属性源
ConfigurableApplicationContextSpring 应用上下文,负责 Bean 的管理
AutoConfigurationImportSelector自动配置类的选择和导入
Embedded Web Server内嵌 Web 服务器(Tomcat/Jetty/Undertow)

入口方法 SpringApplication.run()

静态便捷方法

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

SpringApplication.run() 是一个静态辅助方法,其内部执行流程:

java
public static ConfigurableApplicationContext run(Class<?> primarySource, String[] args) {
    return run(new SpringApplication(primarySource), args);
}

@SpringBootApplication 注解分解

该组合注解等价于:

java
@SpringBootConfiguration      // @Configuration,标记为配置类
@EnableAutoConfiguration     // 启用自动配置
@ComponentScan              // 组件扫描
public @interface SpringBootApplication {
    // ...
}

SpringApplication 构造函数初始化

当创建 SpringApplication 实例时,会执行以下初始化操作:

java
public SpringApplication(Class<?>... primarySources) {
    this(null, primarySources);
}

public SpringApplication(@Nullable ResourceLoader resourceLoader, Class<?>... primarySources) {
    Assert.notEmpty(primarySources, "At least one primary source must be specified");
    
    // 1. 确定主配置类
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    
    // 2. 推断应用类型(标准/Servlet/反应式/WebFlux)
    this.applicationMode = deduceApplicationMode();
    
    // 3. 推断并设置 ClassLoader
    this.classLoader = Thread.currentThread().getContextClassLoader();
    
    // 4. 初始化主要监听器
    setInitializers((Collection) Collections.emptyList());
    setListeners(Collections.emptyList());
    
    // 5. 推断 Main 方法所在类
    this.mainApplicationClass = deduceMainApplicationClass();
    
    // 6. 设置默认 banner
    this.banner = (Banner) new ConsoleBanner();
    this.bannerMode = Banner.Mode.CONSOLE;
    
    // 7. 设置日志系统
    this.logFileName = null;
}

应用类型推断

java
private ApplicationMode deduceApplicationMode() {
    if (isWebApplication()) {
        if (isReactiveWebApplication()) {
            return ApplicationMode.REACTIVE_WEB;
        }
        return ApplicationMode.SERVLET;
    }
    return ApplicationMode.NONE;
}

run() 方法核心流程

这是整个启动流程的核心方法,包含完整的启动步骤:

java
public ConfigurableApplicationContext run(String... args) {
    // ==================== 步骤 1: 创建启动监听器 ====================
    long startTime = System.nanoTime();
    SpringApplicationRunListeners listeners = getRunListeners(args);
    
    // ==================== 步骤 2: 发布启动开始事件 ====================
    listeners.starting();
    
    // ==================== 步骤 3: 准备 Environment ====================
    ConfigurableEnvironment environment = prepareEnvironment(listeners, args);
    
    // ==================== 步骤 4: 打印 Banner ====================
    if (this.bannerMode != Mode.OFF) {
        printBanner(environment);
    }
    
    // ==================== 步骤 5: 创建 ApplicationContext ====================
    ConfigurableApplicationContext context = createApplicationContext();
    
    // ==================== 步骤 6: 准备 ApplicationContext ====================
    prepareContext(context, environment, listeners, args);
    
    // ==================== 步骤 7: 刷新上下文 ====================
    refreshContext(context);
    
    // ==================== 步骤 8: 刷新后处理 ====================
    afterRefresh(context, args);
    
    // ==================== 步骤 9: 发布启动完成事件 ====================
    listeners.started(context);
    
    try {
        // ==================== 步骤 10: 执行 CommandLineRunner/ApplicationRunner ====================
        callRunners(context, args);
    }
    catch (Throwable ex) {
        throw new IllegalStateException(ex);
    }
    
    // ==================== 步骤 11: 发布就绪事件 ====================
    listeners.ready(context);
    
    // 记录启动时间
    Duration timeTaken = Duration.ofNanos(System.nanoTime() - startTime);
    
    return context;
}

启动器监听器 (ApplicationListener)

SpringApplicationRunListeners

java
private SpringApplicationRunListeners getRunListeners(String[] args) {
    Set<Class<? extends ApplicationListener<?>>> listenerClasses = getSpringFactoriesInstances(
        ApplicationListener.class);
    
    // 按顺序排序监听器
    List<ApplicationListener<?>> listeners = new ArrayList<>();
    for (Class<? extends ApplicationListener<?>> listenerClass : listenerClasses) {
        listeners.add(instantiate(listenerClass, args, this));
    }
    
    return new SpringApplicationRunListeners(this, listeners);
}

关键内置监听器

监听器职责
LoggingApplicationListener初始化日志系统,最早执行的监听器
ConfigDataListeners配置数据加载监听
LiveReloadServerApplicationListener热重载支持
EventPublishingRunListener事件发布的包装器

LoggingApplicationListener

作为第一个被调用的监听器,它负责在环境完全初始化之前设置基本的日志能力:

java
@Override
public void onApplicationStartingEvent(ApplicationStartingEvent event) {
    initialize(event.getBootstrapContext(), 
               event.getArgs(), 
               SpringApplication.class.getClassLoader());
}

private void initialize(ConfigurableBootstrapContext bootstrapContext,
                       String[] args, 
                       ClassLoader classLoader) {
    // 1. 创建临时环境用于日志配置
    ConfigurableEnvironment environment = new StandardEnvironment();
    configureEnvironment(args, environment);
    
    // 2. 获取日志系统实现(Logback/Log4j2等)
    LoggingSystem loggingSystem = LoggingSystemFactory.getLoggingSystem(classLoader);
    
    // 3. 初始化日志系统
    loggingSystem.initialize(getInitializationContext(environment),
                            getLoggingConfigLocation(environment),
                            LogFile.get(environment.getPropertyResolver()));
}

环境准备 (Environment Preparation)

prepareEnvironment() 方法

java
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
                                                   String[] args) {
    // 1. 创建可配置环境
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    
    // 2. 配置环境(设置 PropertySources)
    configureEnvironment(args, environment);
    
    // 3. 发布环境准备事件
    listeners.environmentPrepared(environment);
    
    // 4. 重新绑定主类(处理 Profile 相关逻辑)
    bindToSpringApplication(environment);
    
    return environment;
}

EnvironmentPostProcessor

在环境准备完成后,会执行所有注册的 EnvironmentPostProcessor

java
// 从 META-INF/spring.factories 加载
Set<Class<? extends EnvironmentPostProcessor>> processors = 
    getSpringFactoriesInstances(EnvironmentPostProcessor.class);

for (EnvironmentPostProcessor processor : processors) {
    processor.postProcessEnvironment(environment, application);
}

重要 EnvironmentPostProcessor

Processor功能
ConfigDataEnvironmentPostProcessor加载配置数据(Spring Boot 2.4+)
SharedEntityManagerBeanEnvironmentPostProcessorJPA 配置处理
BindingValidationEnvironmentPostProcessor绑定验证
SpringBootEnvCommandlineArgsProcessor命令行参数处理

配置数据加载机制 (ConfigData Loading)

ConfigData 新架构(Spring Boot 2.4+)

Spring Boot 2.4 引入了全新的配置加载机制,取代了原来的 bootstrap.jar 方式。

ConfigDataEnvironmentPostProcessor

java
public void postProcessEnvironment(ConfigurableEnvironment environment,
                                   SpringApplication application) {
    // 使用 ConfigData 机制加载配置
    applyTo(environment, null, null, Collections.emptyList());
}

配置加载优先级顺序

1. 命令行参数 (Command Line Arguments)
2. 来自 java:comp/env 的 JNDI 属性
3. Java 系统属性 (System.getProperties())
4. 操作系统环境变量
5. 随机属性值 (random.* 属性)
6. jar 包外部的 application-{profile}.properties/yml
7. jar 包内部的 application-{profile}.properties/yml
8. jar 包外部的 application.properties/yml
9. jar 包内部的 application.properties/yml
10. @Configuration 类上的 @PropertySource
11. 默认属性 (SpringApplication.setDefaultProperties)

ConfigDataLoader

java
public interface ConfigDataLoader<R extends ConfigDataResource> {
    // 判断资源是否可加载
    default boolean isLoadable(ConfigDataLoaderContext context, R resource) {
        return true;
    }
    
    // 加载配置数据
    @Nullable
    ConfigData load(ConfigDataLoaderContext context, R resource) 
        throws IOException, ConfigDataResourceNotFoundException;
}

配置文件位置(由高到低优先级)

./config/
./
classpath:/config/
classpath:/

ApplicationContext 创建与初始化

上下文类型选择

java
protected ConfigurableApplicationContext createApplicationContext() {
    Class<?> contextClass = this.contextClass;
    
    if (this.applicationMode == ApplicationMode.SERVLET) {
        // Servlet 应用使用 ServletWebServerApplicationContext
        contextClass = ServletWebServerApplicationContext.class;
    }
    else if (this.applicationMode == ApplicationMode.REACTIVE_WEB) {
        // 响应式应用使用 ReactorWebApplicationContext
        contextClass = ReactiveWebServerApplicationContext.class;
    }
    
    if (contextClass == null) {
        // 默认使用 AnnotationConfigApplicationContext
        contextClass = AnnotationConfigApplicationContext.class;
    }
    
    return (ConfigurableApplicationContext) instantiate(contextClass);
}

上下文初始化器

java
protected void prepareContext(ConfigurableApplicationContext context,
                             ConfigurableEnvironment environment,
                             SpringApplicationRunListeners listeners,
                             String[] args) {
    // 1. 设置 Environment
    context.setEnvironment(environment);
    
    // 2. 应用 ApplicationContextInitializer
    postProcessApplicationContext(context);
    applyInitializers(context);
    
    // 3. 发布上下文初始化事件
    listeners.contextInitialized(context);
}

ContextIdApplicationContextInitializer

java
public void initialize(ConfigurableApplicationContext applicationContext) {
    String id = applicationContext.getEnvironment()
        .getProperty("spring.application.name", "application");
    applicationContext.setId(id);
}

自动配置 (Auto-Configuration)

@EnableAutoConfiguration 原理

java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    // ...
}

AutoConfigurationImportSelector

这是自动配置的核心类,负责选择和导入符合条件的配置类:

java
public class AutoConfigurationImportSelector implements DeferredImportSelector {
    
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // 1. 加载所有自动配置类候选
        List<String> configurations = getCandidateConfigurations(annotationMetadata);
        
        // 2. 应用排除规则
        configurations.removeAll(getExcludes(annotationMetadata));
        
        // 3. 应用过滤规则
        return AutConfigurationImportFilter.filter(configurations);
    }
    
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata) {
        // 从 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 加载
        return SpringFactoriesLoader.loadFactoryNames(
            this.beanClassLoader, 
            AutoConfiguration.class.getName());
    }
}

条件注解体系

注解说明
@ConditionalOnClass当指定类在类路径中存在时匹配
@ConditionalOnMissingClass当指定类不在类路径中时匹配
@ConditionalOnProperty当指定属性存在且值匹配时匹配
@ConditionalOnBean当指定 Bean 已注册时匹配
@ConditionalOnMissingBean当指定 Bean 未注册时匹配(最重要)
@ConditionalOnSingleCandidate当只有一个候选 Bean 时匹配
@ConditionalOnExpressionSpEL 表达式结果为 true 时匹配
@ConditionalOnResource指定资源存在时匹配
@ConditionalOnWebApplicationWeb 应用时匹配
@ConditionalOnNotWebApplication非 Web 应用时匹配

自动配置示例

java
@Configuration
@ConditionalOnClass(HttpServlet.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnProperty(prefix = "server", name = "port", havingValue = "0", matchIfMissing = true)
@EnableConfigurationProperties(ServerProperties.class)
public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(
            Environment environment,
            ServerProperties serverProperties,
            TomcatServerProperties tomcatProperties) {
        return new TomcatWebServerFactoryCustomizer(environment, 
                                                   serverProperties, 
                                                   tomcatProperties);
    }
}

上下文刷新 (Context Refresh)

这是整个启动过程中最复杂的一步,涉及大量内部操作:

java
private void refreshContext(ConfigurableApplicationContext context) {
    refresh(context);
}

AbstractApplicationContext.refresh() 详细流程

java
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // ==================== 步骤 1: 准备刷新 ====================
        prepareRefresh();
        
        // ==================== 步骤 2: 获取 BeanFactory ====================
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        
        // ==================== 步骤 3: 准备 BeanFactory ====================
        prepareBeanFactory(beanFactory);
        
        try {
            // ==================== 步骤 4: 子类扩展点 ====================
            postProcessBeanFactory(beanFactory);
            
            // ==================== 步骤 5: 执行 BeanFactoryPostProcessor ====================
            invokeBeanFactoryPostProcessors(beanFactory);
            
            // ==================== 步骤 6: 注册 BeanPostProcessor ====================
            registerBeanPostProcessors(beanFactory);
            
            // ==================== 步骤 7: 初始化消息源 ====================
            initMessageSource();
            
            // ==================== 步骤 8: 初始化事件广播器 ====================
            initApplicationEventMulticaster();
            
            // ==================== 步骤 9: 初始化子上下文 ====================
            onRefresh();
            
            // ==================== 步骤 10: 注册监听器 ====================
            registerListeners();
            
            // ==================== 步骤 11: 实例化剩余单例 Bean ====================
            finishBeanFactoryInitialization(beanFactory);
            
            // ==================== 步骤 12: 完成刷新 ====================
            finishRefresh();
        }
        catch (BeansException ex) {
            destroyBeans();
            cancelRefresh(ex);
            throw ex;
        }
        finally {
            resetCommonCaches();
        }
    }
}

关键步骤详解

步骤 1: prepareRefresh()

java
protected void prepareRefresh() {
    this.startupDate = System.currentTimeMillis();
    this.closed.set(false);
    this.active.set(true);
    
    // 验证并解析 Environment 中的属性
    getEnvironment().resolveRequiredPlaceholders();
    
    // 添加 StartupStep 用于监控
}

步骤 2: obtainFreshBeanFactory()

java
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    // 刷新 BeanFactory,对于 AnnotationConfig 基于的上下文,
    // 这会触发配置类的处理和 BeanDefinition 的注册
    getBeanFactory().refreshBeanDefinitions();
    return getBeanFactory();
}

步骤 3: prepareBeanFactory()

java
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    // 设置 ClassLoader
    beanFactory.setClassLoader(getClassLoader());
    
    // 添加 BeanPostProcessor(基础设施相关的)
    beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    
    // 忽略某些自动依赖
    beanFactory.ignoreDependencyExplicitInterface(
        Environment.class, 
        ResourceLoader.class, 
        ApplicationEventPublisher.class);
    
    // 添加 BeanPostProcessor 检查器
    beanFactory.addBeanPostProcessor(new InstantiationAwareBeanPostProcessorAdapter());
}

步骤 5: invokeBeanFactoryPostProcessors()

这是非常关键的步骤,执行所有 BeanFactoryPostProcessor

java
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    // 1. 执行 PriorityOrdered 的 BFP
    invokeBeanFactoryPostProcessors(beanFactory, 
        beanFactory.getBeanPostProcessors(PriorityOrdered.class));
    
    // 2. 执行 Ordered 的 BFP
    invokeBeanFactoryPostProcessors(beanFactory, 
        beanFactory.getBeanPostProcessors(Ordered.class));
    
    // 3. 执行剩余的 BFP
    String[] names = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, 
                                                     false, false);
    for (String name : names) {
        if (!processed.contains(name)) {
            BeanFactoryPostProcessor bfp = beanFactory.getBean(name, BeanFactoryPostProcessor.class);
            bfp.postProcessBeanFactory(beanFactory);
        }
    }
    
    // 4. 执行 ConfigurationClassPostProcessor(处理@Configuration类)
    // 5. 执行 PropertySourcesPlaceholderConfigurer(占位符解析)
}

步骤 6: registerBeanPostProcessors()

java
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    String[] names = beanFactory.getBeanNamesForType(BeanPostProcessor.class, false, false);
    
    for (String name : names) {
        Object bp = beanFactory.getBean(name);
        if (bp instanceof BeanPostProcessor) {
            beanFactory.addBeanPostProcessor((BeanPostProcessor) bp);
        }
    }
}

重要的 BeanPostProcessor

PostProcessor职责
ConfigurationClassPostProcessor处理 @Configuration 类
AutowiredAnnotationBeanPostProcessor处理 @Autowired 注入
CommonAnnotationBeanPostProcessor处理 @PostConstruct/@PreDestroy
ConfigurationPropertiesBindingPostProcessor绑定 @ConfigurationProperties
ScopedProxyProcessor处理作用域代理

ConfigurationClassPostProcessor

java
public class ConfigurationClassPostProcessor implements BeanFactoryPostProcessor {
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 解析所有@Configuration类及其@Import、@ComponentScan等注解
        ConfigurationClassParser parser = new ConfigurationClassParser(metadataReader);
        parser.parse(this.configurationClasses);
        
        // 将解析结果转换为 BeanDefinition 并注册
        ConfigurationClassBeanDefinitionReader reader = 
            new ConfigurationClassBeanDefinitionReader(beanFactory, parser.getConfigurationClasses());
        reader.loadBeanDefinitions();
    }
}

配置类解析过程

1. 读取主配置类 (@SpringBootApplication)
2. 解析 @ComponentScan -> 发现组件并注册为 BeanDefinition
3. 解析 @EnableAutoConfiguration -> 导入 AutoConfigurationImportSelector
4. AutoConfigurationImportSelector.selectImports() -> 加载所有自动配置类
5. 应用 @Conditional 条件过滤
6. 解析每个配置类的 @Bean 方法
7. 注册所有 BeanDefinition 到 BeanFactory

步骤 11: finishBeanFactoryInitialization()

java
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // 1. 初始化 ConversionService
    beanFactory.addBeanPostProcessor(new ConversionServiceBeanPostProcessor());
    
    // 2. 初始化 LoadTimeWeaver
    
    // 3. 预先实例化所有单例 Bean(除了工厂 Bean)
    beanFactory.preInstantiateSingletons();
}
preInstantiateSingletons()
java
public void preInstantiateSingletons() throws BeansException {
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
    
    for (String beanName : beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        
        // 跳过非单例、抽象、非延迟加载的 Bean
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                // 处理工厂 Bean
                FactoryBean<?> factory = getResolvedFactoryBean(beanName);
                Object bean = factory.getObject();
            } else {
                // 获取普通 Bean(触发完整生命周期)
                getBean(beanName);
            }
        }
    }
}

步骤 12: finishRefresh()

java
protected void finishRefresh() {
    // 清除资源缓存
    clearResourceCaches();
    
    // 发布 ContextRefreshedEvent
    publishEvent(new ContextRefreshedEvent(this));
    
    // 注册 LiveBeansView MBean(JMX 支持)
    LiveBeansView.registerApplicationContext(this);
}

Bean 生命周期

完整生命周期顺序

1. 实例化 (Instantiation)
   └─> 调用构造函数或工厂方法

2. 属性填充 (Populate Bean Properties)
   └─> 依赖注入 (@Autowired)

3. BeanNameAware.setBeanName()
   └─> 如果 Bean 实现了 BeanNameAware

4. BeanFactoryAware.setBeanFactory()
   └─> 如果 Bean 实现了 BeanFactoryAware

5. ApplicationContextAware.setApplicationContext()
   └─> 如果 Bean 实现了 ApplicationContextAware

6. BeanPostProcessor.postProcessBeforeInitialization()
   └─> 所有 BPP 的 before 方法

7. InitializingBean.afterPropertiesSet()
   └─> 如果实现了 InitializingBean

8. @PostConstruct 方法
   └─> 如果有标注的方法

9. 自定义 init-method
   └─> 如果在配置中指定

10. BeanPostProcessor.postProcessAfterInitialization()
    └─> 所有 BPP 的 after 方法(AOP 代理在此处创建)

11. Bean 就绪可用

12. (销毁时)@PreDestroy 方法

13. (销毁时)DisposableBean.destroy()

14. (销毁时)自定义 destroy-method

Aware 接口

接口回调方法说明
BeanNameAwaresetBeanName(String)设置 Bean 的名称
BeanFactoryAwaresetBeanFactory(BeanFactory)注入 BeanFactory
ApplicationContextAwaresetApplicationContext(ApplicationContext)注入 ApplicationContext
ResourceLoaderAwaresetResourceLoader(ResourceLoader)注入资源加载器
ApplicationEventPublisherAwaresetApplicationEventPublisher(...)注入事件发布器

Web 容器启动

ServletWebServerApplicationContext

对于 Web 应用,使用的是特殊的 ApplicationContext:

java
public class ServletWebServerApplicationContext extends WebApplicationContext {
    
    @Override
    protected void onRefresh() {
        super.onRefresh();
        // 创建和启动嵌入式 Web 服务器
        refreshWebServer();
    }
    
    private void refreshWebServer() {
        if (this.webServer == null) {
            // 创建新的 Web 服务器
            this.webServer = startWebServer();
        }
    }
    
    protected WebServer startWebServer() {
        // 获取 WebServerFactoryBean
        WebServer webServer = this.beanFactory.getBean(WebServer.class);
        return webServer;
    }
}

嵌入式服务器创建流程

1. 根据 classpath 选择服务器类型(Tomcat/Jetty/Undertow)
2. 创建对应的 WebServerFactory
3. 应用 WebServerFactoryCustomizer 进行定制
4. 创建 ServletContext
5. 注册 DispatcherServlet
6. 启动服务器并监听端口

Tomcat 自动配置

java
@Configuration
@ConditionalOnClass({Servlet.class, Tomcat.class})
@ConditionalOnMissingBean({ServletWebServerFactory.class})
public class TomcatWebServerFactoryAutoConfiguration {
    
    @Bean
    @ConditionalOnMissingBean
    public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
        return new TomcatServletWebServerFactory();
    }
    
    @Bean
    @ConditionalOnMissingBean
    public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(
            Environment environment,
            ServerProperties serverProperties,
            TomcatServerProperties tomcatProperties) {
        return new TomcatWebServerFactoryCustomizer(environment, 
                                                   serverProperties, 
                                                   tomcatProperties);
    }
}

WebServerFactoryCustomizer

java
public class TomcatWebServerFactoryCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
    
    @Override
    public void customize(TomcatServletWebServerFactory factory) {
        // 应用通用服务器属性
        this.serverProperties.apply(factory);
        
        // 应用 Tomcat 特定属性
        this.tomcatProperties.addAdditionalTomcatConnectors(factory);
        
        // 配置连接器
        factory.addConnectorCustomizers(connector -> {
            this.tomcatProperties.configureConnector(connector);
        });
    }
}

启动完成回调

afterRefresh()

java
protected void afterRefresh(ConfigurableApplicationContext context, String[] args) {
    // ServletWebServerApplicationContext 在此处启动 Web 服务器
    if (context instanceof WebServerApplicationContext wsc) {
        try {
            WebServer webServer = wsc.getWebServer();
            if (webServer != null) {
                webServer.start();
            }
        }
        catch (Throwable ex) {
            throw new IllegalStateException("Failed to start WebServer", ex);
        }
    }
}

执行 Runners

java
private void callRunners(ConfigurableApplicationContext context, String[] args) {
    Collection<? extends CommandLineRunner> commandLineRunners = 
        context.getBeansOfType(CommandLineRunner.class).values();
    Collection<? extends ApplicationRunner> applicationRunners = 
        context.getBeansOfType(ApplicationRunner.class).values();
    
    // 合并并按顺序排序
    List<Runnable> runners = new ArrayList<>();
    runners.addAll(commandLineRunners);
    runners.addAll(applicationRunners);
    sortRunners(runners);
    
    // 执行所有 runners
    for (Runnable runner : runners) {
        try {
            runner.run();
        }
        catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }
}

CommandLineRunner vs ApplicationRunner

java
// CommandLineRunner - 接收原始命令行参数
public interface CommandLineRunner {
    void run(String... args) throws Exception;
}

// ApplicationRunner - 接收封装后的参数
public interface ApplicationRunner {
    void run(ApplicationArguments args) throws Exception;
}

应用事件生命周期

Spring Boot 定义了完整的应用生命周期事件:

事件发生顺序

┌─────────────────────────────────────────────────────────────┐
│ 1. ApplicationStartingEvent                                 │
│    └─ 最早发布,此时只有 SpringApplication 可用                 │
├─────────────────────────────────────────────────────────────┤
│ 2. ApplicationEnvironmentPreparedEvent                      │
│    └─ Environment 已准备完成                                  │
├─────────────────────────────────────────────────────────────┤
│ 3. ApplicationContextInitializedEvent                       │
│    └─ ApplicationContext 已创建并初始化                        │
├─────────────────────────────────────────────────────────────┤
│ 4. ApplicationPreparedEvent                                 │
│    └─ 上下文已准备,但未刷新                                   │
├─────────────────────────────────────────────────────────────┤
│ 5. ApplicationStartedEvent                                  │
│    └─ 上下文已刷新,Runner 尚未执行                              │
├─────────────────────────────────────────────────────────────┤
│ 6. AvailabilityChangeEvent (LivenessState.CORRECT)          │
│    └─ 应用存活                                                 │
├─────────────────────────────────────────────────────────────┤
│ 7. ApplicationReadyEvent                                    │
│    └─ Runner 已执行,应用完全就绪                               │
├─────────────────────────────────────────────────────────────┤
│ 8. AvailabilityChangeEvent (ReadinessState.ACCEPTING_TRAFFIC)│
│    └─ 可以接受流量                                             │
└─────────────────────────────────────────────────────────────┘

异常情况:
┌─────────────────────────────────────────────────────────────┐
│ ApplicationFailedEvent                                      │
│    └─ 启动失败时发布                                          │
└─────────────────────────────────────────────────────────────┘

事件监听示例

java
@Component
public class StartupEventListener implements ApplicationListener<ApplicationReadyEvent> {
    
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        // 应用完全就绪后的处理逻辑
        ApplicationContext context = event.getApplicationContext();
        Duration timeTaken = event.getTimeTaken();
        // ...
    }
}

优雅关闭 (Graceful Shutdown)

关闭钩子注册

java
public ConfigurableApplicationContext run(String... args) {
    // ...
    
    // 注册 JVM 关闭钩子
    shutdownHooks.addCloseHook(context::close);
    
    // 或者使用传统的 shutdown hook
    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
        try {
            context.close();
        }
        catch (Exception e) {
            // 处理异常
        }
    }));
    
    // ...
}

上下文关闭流程

java
public void close() {
    synchronized (this.startupShutdownMonitor) {
        doClose();
    }
}

protected void doClose() {
    if (this.active.compareAndSet(true, false)) {
        // 1. 发布 ContextClosedEvent
        publishEvent(new ContextClosedEvent(this));
        
        // 2. 关闭嵌入式 Web 服务器
        if (this.webServer != null) {
            this.webServer.stop();
        }
        
        // 3. 销毁所有单例 Bean
        destroyBeans();
        
        // 4. 关闭父上下文
        closeParent();
        
        // 5. 发布 ClosedEvent
        publishEvent(new ClosedEvent(this));
    }
}

Bean 销毁回调

java
// 方式 1: @PreDestroy
@Component
public class MyBean {
    @PreDestroy
    public void cleanup() {
        // 清理资源
    }
}

// 方式 2: DisposableBean
@Component
public class MyBean implements DisposableBean {
    @Override
    public void destroy() throws Exception {
        // 清理资源
    }
}

// 方式 3: Closeable/AutoCloseable
@Component
public class MyBean implements Closeable {
    @Override
    public void close() throws Exception {
        // 清理资源
    }
}

// 方式 4: 自定义 destroy-method
@Bean(destroyMethod = "shutdown")
public MyBean myBean() {
    return new MyBean();
}

退出码机制

java
@Component
public class ExitCodeBean implements ExitCodeGenerator {
    
    @Override
    public int getExitCode() {
        // 返回特定的退出码
        return 100;
    }
}

// 在 SpringApplication.exit() 中使用
int exitCode = SpringApplication.exit(context, () -> 100);
System.exit(exitCode);

启动流程图

┌──────────────────────────────────────────────────────────────────────────────┐
│                           Spring Boot 启动流程                                │
└──────────────────────────────────────────────────────────────────────────────┘


                    ┌────────────────────────────────┐
                    │  main() 方法调用               │
                    │  SpringApplication.run()       │
                    └────────────────┬───────────────┘


                    ┌────────────────────────────────┐
                    │  1. 创建 SpringApplication      │
                    │     - 推断应用类型              │
                    │     - 设置 ClassLoader         │
                    └────────────────┬───────────────┘


                    ┌────────────────────────────────┐
                    │  2. 创建启动监听器              │
                    │     SpringApplicationRunListeners│
                    └────────────────┬───────────────┘


                    ┌────────────────────────────────┐
                    │  3. 发布 ApplicationStartingEvent│
                    │     LoggingApplicationListener  │
                    │     初始化日志系统              │
                    └────────────────┬───────────────┘


                    ┌────────────────────────────────┐
                    │  4. 准备 Environment           │
                    │     - 创建 StandardEnvironment │
                    │     - 加载 PropertySources     │
                    │     - 执行 EnvironmentPostProcessor│
                    │     - ConfigDataEnvironmentPostProcessor│
                    └────────────────┬───────────────┘


                    ┌────────────────────────────────┐
                    │  5. 发布 ApplicationEnvironmentPreparedEvent│
                    └────────────────┬───────────────┘


                    ┌────────────────────────────────┐
                    │  6. 打印 Banner                │
                    └────────────────┬───────────────┘


                    ┌────────────────────────────────┐
                    │  7. 创建 ApplicationContext    │
                    │     - ServletWebServerApplicationContext│
                    │     - AnnotationConfigApplicationContext│
                    └────────────────┬───────────────┘


                    ┌────────────────────────────────┐
                    │  8. 准备 ApplicationContext    │
                    │     - 设置 Environment         │
                    │     - 执行 ApplicationContextInitializer│
                    └────────────────┬───────────────┘


                    ┌────────────────────────────────┐
                    │  9. 发布 ApplicationContextInitializedEvent│
                    └────────────────┬───────────────┘


                    ┌────────────────────────────────┐
                    │  10. 加载 BeanDefinition       │
                    │      (refresh() 内部)           │
                    └────────────────┬───────────────┘


                    ┌─────────────────────────────────────────────────────┐
                    │                   refresh() 详细流程                  │
                    ├─────────────────────────────────────────────────────┤
                    │  10.1 prepareRefresh()                              │
                    │  10.2 obtainFreshBeanFactory()                       │
                    │  10.3 prepareBeanFactory()                           │
                    │  10.4 postProcessBeanFactory()                       │
                    │  10.5 invokeBeanFactoryPostProcessors()              │
                    │         - ConfigurationClassPostProcessor            │
                    │         - 处理 @Configuration                         │
                    │         - 处理 @ComponentScan                         │
                    │         - AutoConfigurationImportSelector             │
                    │         - 加载自动配置类                              │
                    │         - 应用 @Conditional 条件                       │
                    │  10.6 registerBeanPostProcessors()                   │
                    │  10.7 initMessageSource()                            │
                    │  10.8 initApplicationEventMulticaster()              │
                    │  10.9 onRefresh() ← 创建 WebServer                    │
                    │  10.10 registerListeners()                           │
                    │  10.11 finishBeanFactoryInitialization()             │
                    │         - preInstantiateSingletons()                 │
                    │         - Bean 完整生命周期                           │
                    │  10.12 finishRefresh()                               │
                    └─────────────────────────────────────────────────────┘


                    ┌────────────────────────────────┐
                    │  11. 发布 ApplicationPreparedEvent│
                    └────────────────┬───────────────┘


                    ┌────────────────────────────────┐
                    │  12. afterRefresh()            │
                    │      - 启动嵌入式 Web 服务器       │
                    │      - Tomcat/Jetty/Undertow   │
                    └────────────────┬───────────────┘


                    ┌────────────────────────────────┐
                    │  13. 发布 ApplicationStartedEvent│
                    └────────────────┬───────────────┘


                    ┌────────────────────────────────┐
                    │  14. 执行 ApplicationRunner/    │
                    │      CommandLineRunner         │
                    └────────────────┬───────────────┘


                    ┌────────────────────────────────┐
                    │  15. 发布 ApplicationReadyEvent │
                    │      应用完全就绪!              │
                    └────────────────┬───────────────┘


                    ┌────────────────────────────────┐
                    │  16. 注册关闭钩子               │
                    │      - JVM Shutdown Hook      │
                    │      - 优雅关闭支持            │
                    └────────────────────────────────┘

关键配置文件位置

Spring Boot 3.x 自动配置加载

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

Spring Boot 2.x 及更早版本

META-INF/spring.factories

格式示例

# Auto Configuration
org.springframework.boot.autoconfigure.AutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
...

# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.env.SpringBootEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPostProcessor,\
org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor,\
...

# Application Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.devtools.restart.RestartApplicationListener,\
org.springframework.boot.logging.LoggingApplicationListener,\
...

性能优化建议

1. 减少自动配置类

properties
# 排除不需要的自动配置
spring.autoconfigure.exclude=\
    org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
    org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration

2. 使用延迟加载

java
@Configuration
public class LazyConfig {
    
    @Bean
    @Lazy
    public HeavyBean heavyBean() {
        return new HeavyBean();
    }
}

3. 并行 Bean 初始化(Spring Boot 3.2+)

properties
# 启用并行 Bean 初始化
spring.main.lazy-initialization=true

4. 分层启动

properties
# 仅加载必要的配置层
spring.config.import=optional:configserver:http://config-server:8888

调试技巧

1. 查看自动配置报告

properties
debug=true

2. 追踪配置加载

properties
logging.level.org.springframework.boot.context.config=TRACE

3. 查看 Condition 评估

properties
logging.level.org.springframework.boot.autoconfigure=DEBUG

4. 生成条件评估报告

java
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        ConfigurableApplicationContext context = 
            SpringApplication.run(App.class, args);
        
        // 输出自动配置报告
        AutoConfigurationReport autoConfigurationReport = 
            AutoConfigurationReport.get(context);
        System.out.println(autoConfigurationReport.formattedOutput());
    }
}

一句话总结

Spring Boot 启动本质上是:创建 SpringApplication → 初始化日志和环境 → 构建 ApplicationContext → 通过 Condition 机制智能加载自动配置 → 刷新上下文触发 Bean 完整生命周期 → 启动 Web 容器 → 执行启动回调 → 应用就绪。


本文档基于 Spring Boot 4.0 Snapshot 版本编写,适用于 Spring Boot 2.x/3.x/4.x 系列版本的核心启动流程理解。

更新于:

note