深入剖析Spring Boot应用启动全流程

目录

前言

启动流程概览

一、第一阶段:初始化SpringApplication

二、第二阶段:运行SpringApplication

三、第三阶段:环境准备

四、第四阶段:创建应用上下文

五、第五阶段:准备应用上下文

六、第六阶段:刷新应用上下文(核心)

七、第七阶段:启动后处理

启动流程图解

[Spring Boot启动流程与自动装配的联系](#Spring Boot启动流程与自动装配的联系)

总结


前言

Spring Boot以其"开箱即用"的特性大大简化了Spring应用的开发部署流程。只需一个main方法和一个简单的SpringApplication.run()调用,我们的应用就能快速启动。但这背后究竟发生了什么?本文将深入剖析Spring Boot应用的完整启动流程,带你理解从点击"运行"到应用完全就绪的每一个关键步骤。


启动流程概览

Spring Boot的启动过程可以概括为以下几个核心阶段:

  1. 初始化SpringApplication实例

  2. 运行SpringApplication

  3. 准备环境设置

  4. 创建应用上下文

  5. 刷新应用上下文(核心)

  6. 执行Runner接口实现

下面我们详细分析每个阶段的具体工作。

一、第一阶段:初始化SpringApplication

当我们调用SpringApplication.run(Application.class, args)时,首先会初始化一个SpringApplication实例

java 复制代码
//代码示例
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return run(new Class<?>[] { primarySource }, args);
}

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

在SpringApplication的构造函数中,会进行以下关键操作:

  1. 推断应用类型:根据类路径下的依赖判断是SERVLET应用(Spring MVC)、REACTIVE应用(WebFlux)还是普通应用

  2. 加载应用上下文初始化器:通过SpringFactoriesLoader从META-INF/spring.factories加载ApplicationContextInitializer

  3. 加载应用监听器:同样通过SpringFactoriesLoader加载ApplicationListener

  4. 推断主配置类:根据堆栈信息找到包含main方法的类

二、第二阶段:运行SpringApplication

run方法是整个启动流程的核心:

java 复制代码
public ConfigurableApplicationContext run(String... args) {
    // 1. 创建启动计时器
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    
    // 2. 初始化默认应用上下文
    ConfigurableApplicationContext context = null;
    
    // 3. 配置headless属性
    configureHeadlessProperty();
    
    // 4. 获取SpringApplicationRunListeners
    SpringApplicationRunListeners listeners = getRunListeners(args);
    
    // 5. 发布应用开始启动事件
    listeners.starting();
    
    try {
        // 6. 准备环境
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
        
        // 7. 打印Banner
        Banner printedBanner = printBanner(environment);
        
        // 8. 创建应用上下文
        context = createApplicationContext();
        
        // 9. 准备应用上下文
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        
        // 10. 刷新应用上下文(核心步骤)
        refreshContext(context);
        
        // 11. 上下文刷新后处理
        afterRefresh(context, applicationArguments);
        
        // 12. 停止计时器
        stopWatch.stop();
        
        // 13. 发布应用启动完成事件
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass)
                .logStarted(getApplicationLog(), stopWatch);
        }
        listeners.started(context);
        
        // 14. 调用ApplicationRunner和CommandLineRunner
        callRunners(context, applicationArguments);
    } catch (Throwable ex) {
        handleRunFailure(context, ex, listeners);
        throw new IllegalStateException(ex);
    }
    
    try {
        listeners.running(context);
    } catch (Throwable ex) {
        handleRunFailure(context, ex, null);
        throw new IllegalStateException(ex);
    }
    return context;
}

三、第三阶段:环境准备

prepareEnvironment()方法负责准备应用运行环境:

  1. 创建环境对象:根据应用类型创建StandardEnvironment或StandardServletEnvironment

  2. 配置环境:配置PropertySources和Profiles

  3. 发布环境准备事件:通过EnvironmentPostProcessorApplicationListener处理

  4. 绑定环境到SpringApplication

  5. 转换配置:将命令行参数转换为PropertySource

  6. 处理ConfigurationProperties:验证和绑定@ConfigurationProperties

四、第四阶段:创建应用上下文

createApplicationContext()根据应用类型创建对应的应用上下文:

  • Servlet应用:AnnotationConfigServletWebServerApplicationContext

  • Reactive应用:AnnotationConfigReactiveWebServerApplicationContext

  • 普通应用:AnnotationConfigApplicationContext

五、第五阶段:准备应用上下文

prepareContext()方法准备创建好的应用上下文:

  1. 设置环境

  2. 后处理上下文:调用ApplicationContextInitializer

  3. 发布上下文准备事件

  4. 注册SpringBootBanner

  5. 设置资源加载器和类加载器

  6. 注册Bean定义

    • 注册主配置类(@SpringBootApplication标注的类)

    • 注册命令行参数Bean

    • 注册Banner Bean

六、第六阶段:刷新应用上下文(核心)

refreshContext()调用的是AbstractApplicationContext的refresh()方法,这是Spring容器的核心生命周期方法:

java 复制代码
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 1. 准备刷新上下文
        prepareRefresh();
        
        // 2. 获取刷新后的BeanFactory
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        
        // 3. 准备BeanFactory使用上下文
        prepareBeanFactory(beanFactory);
        
        try {
            // 4. 允许BeanFactory的后处理
            postProcessBeanFactory(beanFactory);
            
            // 5. 调用BeanFactoryPostProcessor
            invokeBeanFactoryPostProcessors(beanFactory);
            
            // 6. 注册BeanPostProcessor
            registerBeanPostProcessors(beanFactory);
            
            // 7. 初始化MessageSource
            initMessageSource();
            
            // 8. 初始化事件广播器
            initApplicationEventMulticaster();
            
            // 9. 初始化特殊Bean(由子类实现)
            onRefresh();
            
            // 10. 注册监听器
            registerListeners();
            
            // 11. 完成BeanFactory初始化,实例化所有非懒加载单例
            finishBeanFactoryInitialization(beanFactory);
            
            // 12. 完成刷新,发布上下文刷新事件
            finishRefresh();
        } catch (BeansException ex) {
            // 13. 销毁已创建的单例Bean
            destroyBeans();
            
            // 14. 重置激活标志
            cancelRefresh(ex);
            
            throw ex;
        } finally {
            // 15. 重置Spring核心中的公共内省缓存
            resetCommonCaches();
        }
    }
}

对于Spring Boot来说,onRefresh()方法尤为重要,这里会创建嵌入式Web服务器:

java 复制代码
protected void onRefresh() {
    super.onRefresh();
    try {
        createWebServer(); // 创建Tomcat、Jetty或Undertow服务器
    } catch (Throwable ex) {
        throw new ApplicationContextException("Unable to start web server", ex);
    }
}

七、第七阶段:启动后处理

刷新完成后,Spring Boot会执行一些后处理操作:

  1. 调用ApplicationRunner和CommandLineRunner:执行应用中定义的Runner实现

  2. 发布应用就绪事件:ApplicationReadyEvent,表示应用已完全启动

  3. 启动完成:此时应用已完全就绪,可以处理请求

启动流程图解

Spring Boot启动流程与自动装配的联系

1.核心关系:自动装配是启动流程的关键环节

简单来说,自动装配是Spring Boot启动流程中的一个核心子过程。没有启动流程提供的环境、上下文和机制,自动装配无法工作;而没有自动装配,Spring Boot的启动就失去了"智能"和"自动化"的特性,退回到了传统Spring应用的繁琐配置模式。

2.自动装配的具体执行时机

自动装配发生在应用上下文刷新阶段,具体在refreshContext()方法中的invokeBeanFactoryPostProcessors(beanFactory)步骤:

java 复制代码
public void refresh() throws BeansException, IllegalStateException {
    // ... 前面的步骤
    invokeBeanFactoryPostProcessors(beanFactory); // 自动装配在这里发生!
    // ... 后续步骤
}

总结

Spring Boot的启动流程是一个精心设计的过程,它将传统的XML配置转换为基于Java的自动配置,通过条件化装配和自动发现机制,极大地简化了Spring应用的开发和部署。理解这个流程不仅有助于我们更好地使用Spring Boot,还能在遇到问题时快速定位和解决。

整个过程体现了Spring Boot的核心设计理念:约定优于配置自动装配微内核架构。通过事件监听机制和扩展点设计,Spring Boot在保持简洁性的同时,也提供了极大的灵活性和可扩展性。