Spring Boot 应用启动时,入口通常是:

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

这个 SpringApplication.run(...) 方法是整个启动流程的核心。我们可以将启动过程分为两个主要阶段:

一、推断阶段(Inference Phase)

这是在 new SpringApplication(...) 构造器中完成的,包括:

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.addCommandLineProperties = true;
        this.addConversionService = true;
        this.headless = true;
        this.additionalProfiles = Collections.emptySet();
        this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
        this.applicationStartup = ApplicationStartup.DEFAULT;
        this.properties = new ApplicationProperties();
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "'primarySources' must not be null");
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        this.properties.setWebApplicationType(WebApplicationType.deduceFromClasspath());
        this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }
  • 推断主配置类(primary source)
  • 推断 Web 应用类型(WebApplicationType
  • 设置初始化器(ApplicationContextInitializer
  • 设置监听器(ApplicationListener
  • 推断主类(main class)

这部分是“第一步”,我们重点分析第二步。

二、执行 run 方法的详细流程(Execution Phase)

我们以 Spring Boot 2.7.x / 3.x 的源码为基础,分析 SpringApplication.run(String... args) 方法内部执行的关键步骤。

源码入口(简化版):

public ConfigurableApplicationContext run(String... args) {
    // 1. 创建并启动 StopWatch(计时器)
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    // 2. 初始化上下文容器引用
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    ConfigurableApplicationContext context = null;

    // 3. 配置 Headless 模式
    configureHeadlessProperty();

    // 4. 获取并启动监听器
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting(bootstrapContext, this.mainApplicationClass);

    try {
        // 5. 创建并处理 ApplicationArguments
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

        // 6. 准备 Environment(环境变量、配置文件等)
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
        configureIgnoreBeanInfo(environment);

        // 7. 打印 Banner(可选)
        Banner printedBanner = printBanner(environment);

        // 8. 创建 ApplicationContext(根据 Web 类型决定是 Servlet/Reactive/None)
        context = createApplicationContext();
        context.setApplicationStartup(this.applicationStartup);

        // 9. 准备上下文(加载 Bean 定义、注册单例等)
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

        // 10. 刷新上下文(核心:触发 Spring 容器的 refresh)
        refreshContext(context);

        // 11. 刷新后处理(空方法,可扩展)
        afterRefresh(context, applicationArguments);

        // 12. 停止计时器,发布启动完成事件
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
        }

        // 13. 通知监听器:启动完成
        listeners.started(context, stopWatch.getTotalTimeMillis());

        // 14. 调用 Runner(CommandLineRunner / ApplicationRunner)
        callRunners(context, applicationArguments);

        // 15. 通知监听器:运行中(running)
        listeners.running(context);

        return context;
    } catch (Throwable ex) {
        handleRunFailure(context, ex, listeners);
        throw new IllegalStateException(ex);
    }
}

三、关键步骤详解(结合原理)

1. 创建 Bootstrap Context(引导上下文)

  • Spring Boot 2.4+ 引入了 BootstrapContext,用于支持早期配置(如配置中心拉取配置)。
  • 通常用于 spring-cloud 场景,在普通 Spring Boot 中可能为空。

2. 启动监听器(SpringApplicationRunListeners)

  • 加载 META-INF/spring.factories 中定义的 SpringApplicationRunListener
  • 默认实现是 EventPublishingRunListener,它会将启动过程中的各个阶段包装成事件(如 ApplicationStartingEvent)并发布到事件总线。

3. 准备 Environment

  • 创建 Environment(StandardServletEnvironment / StandardReactiveWebEnvironment / StandardEnvironment)。
  • 绑定命令行参数、系统属性、配置文件(application.properties / yml)。
  • 触发 EnvironmentPostProcessor 对 Environment 进行后处理(如 Spring Cloud Config)。
  • 发布 ApplicationEnvironmentPreparedEvent

4. 创建 ApplicationContext

  • 根据 webApplicationType 创建:
    • AnnotationConfigServletWebServerApplicationContext(Servlet Web)
    • AnnotationConfigReactiveWebServerApplicationContext(Reactive Web)
    • AnnotationConfigApplicationContext(非 Web)

5. prepareContext(准备上下文)

  • 将 Environment 设置到 ApplicationContext。
  • 应用 ApplicationContextInitializer(用户自定义初始化逻辑)。
  • 注册单例 Bean(如 springApplicationArgumentsspringBootBanner)。
  • 加载主配置类(即 @SpringBootApplication 标注的类)为 BeanDefinition。
  • 发布 ApplicationContextInitializedEvent

6. refreshContext(刷新上下文)

  • 调用 AbstractApplicationContext.refresh(),这是 Spring Framework 的核心方法。
  • 关键子步骤包括:
    • invokeBeanFactoryPostProcessors():处理 @Configuration@ComponentScan@Import@PropertySource 等。
    • registerBeanPostProcessors():注册 Bean 后处理器。
    • initMessageSource()initApplicationEventMulticaster()
    • onRefresh()内嵌 Web 容器启动点(如 Tomcat 启动在此处)。
    • registerListeners():注册事件监听器。
    • finishBeanFactoryInitialization()实例化所有非懒加载的单例 Bean
    • finishRefresh():发布 ContextRefreshedEvent,启动 Lifecycle 组件。

注意:refreshContext() 内部还会调用 registerShutdownHook() 注册 JVM 关闭钩子。

7. callRunners

  • 找出所有 CommandLineRunner 和 ApplicationRunner 的 Bean。
  • 按 @Order 或 Ordered 排序后依次执行。
  • 这是应用完全启动后、对外提供服务前的最后扩展点。

8. 发布 running 事件

  • 发布 ApplicationReadyEvent,表示应用已准备好处理请求。

四、总结:run 方法的核心流程图(简化)

run()
├─ 创建 BootstrapContext
├─ 启动监听器 → ApplicationStartingEvent
├─ 准备 Environment → ApplicationEnvironmentPreparedEvent
├─ 创建 ApplicationContext
├─ prepareContext → ApplicationContextInitializedEvent
├─ refreshContext(Spring 容器刷新)
│   ├─ 加载 Bean 定义
│   ├─ 实例化 Bean
│   └─ 启动内嵌 Web 容器(如 Tomcat)
├─ afterRefresh(空钩子)
├─ callRunners(执行 CommandLineRunner / ApplicationRunner)
└─ listeners.running() → ApplicationReadyEvent

五、扩展建议

  • 若想干预启动流程,可通过:

    • 实现 ApplicationContextInitializer
    • 实现 ApplicationListener<...Event>
    • 实现 EnvironmentPostProcessor
    • 实现 CommandLineRunner / ApplicationRunner
  • 调试技巧:在 SpringApplication.run() 处打断点,逐步跟踪上述流程。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐