Spring Boot 应用程序启动时执行流程

关于Spring Boot 应用程序启动时 main 方法的完整执行流程。我会按照方法调用的核心顺序进行描述,并解释每个关键方法的作用。

核心流程总览

在Spring Boot应用中,我们通常会写一个包含main方法的类,并调用SpringApplication.run。

示例代码:

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

整个启动过程可以概括为:构造 SpringApplication 对象 -> 执行 run 方法 -> 启动内嵌服务器 -> 完成应用启动


第一阶段:SpringApplication 实例化

执行方法:new SpringApplication(primarySources)

  1. 执行 this(null, primarySources)

    • 作用:调用内部的构造器。
    • 最主要的部分是 WebApplicationType.deduceFromClasspath() 方法
      • 这个方法的作用是:根据类路径下存在的类来推断应用类型。
      • 它会检查 DispatcherHandlerDispatcherServletServlet 等类的存在性,从而判断应用是 REACTIVE(响应式)、SERVLET(标准的 Servlet Web 应用)还是 NONE(非 Web 应用)。我们最常见的 Spring MVC 应用就是 SERVLET 类型。
  2. 执行 setInitializers 方法

    • 作用 :设置应用初始化器 (ApplicationContextInitializer)。
    • 最主要的部分是 getSpringFactoriesInstances(ApplicationContextInitializer.class) 方法
      • 这个方法的作用是 :使用 Spring 工厂加载机制,从 META-INF/spring.factories 配置文件中加载并实例化所有配置的 ApplicationContextInitializer 实现类。
      • 常见的初始化器如 ConfigurationWarningsApplicationContextInitializer(检查配置警告)、ContextIdApplicationContextInitializer(设置上下文 ID)等。这些初始化器会在 ApplicationContext 刷新之前被调用。
  3. 执行 setListeners 方法

    • 作用 :设置应用监听器 (ApplicationListener)。
    • 最主要的部分同样是 getSpringFactoriesInstances(ApplicationListener.class) 方法
      • 这个方法的作用是 :从 spring.factories 中加载并实例化所有配置的 ApplicationListener
      • 这些监听器用于监听在应用启动过程中发布的各类事件,例如 ApplicationStartedEventApplicationReadyEvent 等。ClearCachesApplicationListener(清除缓存)、FileEncodingApplicationListener(检查文件编码)都是常见的监听器。
  4. 执行 deduceMainApplicationClass 方法

    • 作用 :推导出主应用程序类(即我们写了 main 方法的那个类)。
    • 原理是 :遍历当前调用栈,找到第一个方法名为 main 的类。

至此,SpringApplication 对象构造完毕,它已经准备好了初始化器和监听器。


第二阶段:执行 run 方法

执行方法:SpringApplication.run(primarySources, args)

这是整个启动流程最核心、最复杂的方法。

  1. 执行 getRunListeners 方法并调用 listeners.starting()

    • 作用 :获取 SpringApplicationRunListeners 并发布 ApplicationStartingEvent 事件。
    • 说明SpringApplicationRunListenersSpringApplicationRunListener 的集合,它专门用于监听 SpringApplicationrun 方法执行过程中的关键节点。第一步就是发布应用正在启动的事件。
  2. 执行 prepareEnvironment 方法

    • 作用 :准备和应用环境 (Environment),这是整个应用配置的基础。
    • 最主要的部分是
      • getOrCreateEnvironment():根据应用类型创建 StandardEnvironmentStandardServletEnvironment
      • configureEnvironment(environment, args):配置环境,包括 PropertySources(属性源,如 JVM 系统属性、操作系统环境变量)和 Profiles(配置文件,如 "dev", "prod")。
      • listeners.environmentPrepared(environment):发布 ApplicationEnvironmentPreparedEvent 事件。这是一个极其重要的扩展点 ,监听这个事件的监听器(最著名的是 ConfigFileApplicationListener)会从 application.propertiesapplication.yml 等文件中加载我们自定义的配置属性。
  3. 执行 printBanner 方法

    • 作用:在控制台打印 Spring Boot 的 Banner。
  4. 执行 createApplicationContext 方法

    • 作用 :创建 ApplicationContext(IoC 容器)。
    • 根据第一步推断出的 WebApplicationType ,创建不同类型的上下文。对于 Servlet Web 应用,会创建 AnnotationConfigServletWebServerApplicationContext
  5. 执行 prepareContext 方法

    • 作用 :准备上面创建好的 ApplicationContext
    • 最主要的部分是
      • postProcessApplicationContext(context):后处理应用上下文,例如设置 Bean 名称生成器、资源加载器。
      • applyInitializers(context)应用初始化器 。调用在第一步中加载的所有 ApplicationContextInitializerinitialize 方法,允许我们在容器刷新前对上下文进行自定义。
      • listeners.contextPrepared(context):发布 ApplicationContextInitializedEvent 事件,通知监听器上下文已准备就绪。
      • load(context, sources.toArray(new Object[0])):将主源(即我们的 @SpringBootApplication 注解类)加载到上下文中,为后续的组件扫描和 Bean 定义注册做准备。
      • listeners.contextLoaded(context):发布 ApplicationPreparedEvent 事件,通知监听器上下文已加载完毕。

第三阶段:刷新应用上下文 (最最核心)

执行方法:refreshContext(context)

这个方法内部会调用 AbstractApplicationContext.refresh(),这是 Spring 框架容器初始化的标准流程。

  1. 执行 prepareRefresh() 方法

    • 作用:刷新前的准备工作,例如初始化属性源、验证必要的属性。
  2. 执行 obtainFreshBeanFactory() 方法

    • 作用 :获取或刷新内部的 BeanFactoryDefaultListableBeanFactory)。BeanFactory 是 Spring 容器的基础。
  3. 执行 prepareBeanFactory(beanFactory) 方法

    • 作用 :准备 BeanFactory,配置它的类加载器、后置处理器等标准配置。
  4. 执行 postProcessBeanFactory(beanFactory) 方法

    • 作用 :允许在 Bean 定义加载完成后、实例化之前,对 BeanFactory 进行后处理。这是一个空方法,供子类扩展。
  5. 执行 invokeBeanFactoryPostProcessors(beanFactory) 方法

    • 作用这是 Spring Boot 自动配置的魔法入口!
    • 最主要的部分是 :调用所有 BeanFactoryPostProcessor
    • 其中,ConfigurationClassPostProcessor 会解析 @Configuration 注解的类。它会发现我们的主类上的 @SpringBootApplication 注解。
    • @SpringBootApplication 中包含 @EnableAutoConfiguration,后者会导入 AutoConfigurationImportSelector
    • AutoConfigurationImportSelector 会从 META-INF/spring.factories 中加载所有 EnableAutoConfiguration 键对应的自动配置类(如 DataSourceAutoConfiguration, WebMvcAutoConfiguration)。
    • 这些自动配置类根据条件(如类路径下是否存在某个类、是否设置了某个属性等)决定是否生效,并向容器中批量添加 Bean 定义。
  6. 执行 registerBeanPostProcessors(beanFactory) 方法

    • 作用 :注册 BeanPostProcessor。这些处理器会在 Bean 实例化之后、初始化前后 被调用,用于对 Bean 进行增强(如 @Autowired, @PostConstruct 等功能都是通过 BeanPostProcessor 实现的)。
  7. 执行 initMessageSource() 方法

    • 作用:初始化国际化相关的消息源。
  8. 执行 initApplicationEventMulticaster() 方法

    • 作用:初始化应用事件广播器,用于事件发布。
  9. 执行 onRefresh() 方法

    • 作用这是 Spring Boot 创建并启动内嵌 Web 服务器的关键步骤!
    • ServletWebServerApplicationContext 中,此方法被重写。
    • 最主要的部分是 createWebServer() 方法
      • 这个方法的作用是 :从 BeanFactory 中获取 ServletWebServerFactory(如 TomcatServletWebServerFactory)。
      • 调用 factory.getWebServer(...) 方法,这会创建内嵌的 Tomcat/Jetty/Undertow 服务器实例,并初始化 Servlet 容器(初始化 DispatcherServlet 并注册到容器中)。此时,Web 服务器已经创建好,但尚未开始监听端口。
  10. 执行 registerListeners() 方法

    • 作用:注册监听器,将事件监听器注册到第 8 步初始化的事件广播器中。
  11. 执行 finishBeanFactoryInitialization(beanFactory) 方法

    • 作用完成 BeanFactory 的初始化,实例化所有剩余的非懒加载单例 Bean。
    • 这是 IoC 容器依赖注入发生的主要阶段。我们的 Controller、Service、Repository 等组件都在这个阶段被创建和装配。
  12. 执行 finishRefresh() 方法

    • 作用:完成上下文的刷新工作,发布最终事件。
    • 最主要的部分是
      • publishEvent(new ContextRefreshedEvent(this)):发布 ContextRefreshedEvent 事件。
      • ServletWebServerApplicationContext 中,还会调用 finishRefresh() 的一个扩展,最终启动内嵌的 Web 服务器 (例如 TomcatWebServer.start()),开始监听指定的端口。至此,我们的应用已经可以处理 HTTP 请求了。

第四阶段:启动后处理

  1. 执行 afterRefresh(context, applicationArguments) 方法

    • 作用:刷新后处理,默认为空。是一个扩展点。
  2. 执行 listeners.started(context) 方法

    • 作用 :发布 ApplicationStartedEvent 事件,通知所有监听器应用已启动。
  3. 执行 callRunners(applicationArguments) 方法

    • 作用调用 ApplicationRunnerCommandLineRunner 接口的实现类。
    • 这是开发者可以在应用启动后、开始接收流量前,执行一些特定初始化逻辑的常用方式。
  4. 执行 listeners.ready(context, timeTaken) 方法

    • 作用 :发布 ApplicationReadyEvent 事件。这个事件标志着应用已完全启动完毕,处于就绪状态 。它与 ApplicationStartedEvent 的区别在于,此时所有 Bean 都已初始化,内嵌服务器已在运行。
  5. 返回 ApplicationContext

    • 作用 :将已经完全初始化好的 ApplicationContext 返回。

总结

整个流程从 main 方法开始,经历了 环境准备 -> 容器创建 -> Bean定义加载(自动配置) -> Bean实例化(依赖注入) -> 内嵌服务器启动 -> 运行自定义初始化逻辑 等一系列复杂而精密的步骤,最终将一个功能完备的 Spring Boot 应用呈现在我们面前。其中 refreshContext() 是整个流程的心脏,而自动配置和内嵌服务器是 Spring Boot 两大核心特性的实现关键。

相关推荐
bcbnb4 小时前
如何解析iOS崩溃日志:从获取到符号化分析
后端
许泽宇的技术分享4 小时前
当AI学会“说人话“:Azure语音合成技术的魔法世界
后端·python·flask
用户69371750013844 小时前
4.Kotlin 流程控制:强大的 when 表达式:取代 Switch
android·后端·kotlin
用户69371750013844 小时前
5.Kotlin 流程控制:循环的艺术:for 循环与区间 (Range)
android·后端·kotlin
vx_bisheyuange4 小时前
基于SpringBoot的宠物商城网站的设计与实现
spring boot·后端·宠物
bcbnb5 小时前
全面解析网络抓包工具使用:Wireshark和TCPDUMP教程
后端
leonardee5 小时前
Spring Security安全框架原理与实战
java·后端
一个处女座的程序猿O(∩_∩)O5 小时前
Spring Boot、Redis、RabbitMQ 在项目中的核心作用详解
spring boot·redis·java-rabbitmq
q***5185 小时前
Spring Cloud gateway 路由规则
java
回家路上绕了弯5 小时前
包冲突排查指南:从发现到解决的全流程实战
分布式·后端