关于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)
-
执行
this(null, primarySources):- 作用:调用内部的构造器。
- 最主要的部分是
WebApplicationType.deduceFromClasspath()方法 :- 这个方法的作用是:根据类路径下存在的类来推断应用类型。
- 它会检查
DispatcherHandler、DispatcherServlet、Servlet等类的存在性,从而判断应用是REACTIVE(响应式)、SERVLET(标准的 Servlet Web 应用)还是NONE(非 Web 应用)。我们最常见的 Spring MVC 应用就是SERVLET类型。
-
执行
setInitializers方法:- 作用 :设置应用初始化器 (
ApplicationContextInitializer)。 - 最主要的部分是
getSpringFactoriesInstances(ApplicationContextInitializer.class)方法 :- 这个方法的作用是 :使用 Spring 工厂加载机制,从
META-INF/spring.factories配置文件中加载并实例化所有配置的ApplicationContextInitializer实现类。 - 常见的初始化器如
ConfigurationWarningsApplicationContextInitializer(检查配置警告)、ContextIdApplicationContextInitializer(设置上下文 ID)等。这些初始化器会在ApplicationContext刷新之前被调用。
- 这个方法的作用是 :使用 Spring 工厂加载机制,从
- 作用 :设置应用初始化器 (
-
执行
setListeners方法:- 作用 :设置应用监听器 (
ApplicationListener)。 - 最主要的部分同样是
getSpringFactoriesInstances(ApplicationListener.class)方法 :- 这个方法的作用是 :从
spring.factories中加载并实例化所有配置的ApplicationListener。 - 这些监听器用于监听在应用启动过程中发布的各类事件,例如
ApplicationStartedEvent、ApplicationReadyEvent等。ClearCachesApplicationListener(清除缓存)、FileEncodingApplicationListener(检查文件编码)都是常见的监听器。
- 这个方法的作用是 :从
- 作用 :设置应用监听器 (
-
执行
deduceMainApplicationClass方法:- 作用 :推导出主应用程序类(即我们写了
main方法的那个类)。 - 原理是 :遍历当前调用栈,找到第一个方法名为
main的类。
- 作用 :推导出主应用程序类(即我们写了
至此,SpringApplication 对象构造完毕,它已经准备好了初始化器和监听器。
第二阶段:执行 run 方法
执行方法:SpringApplication.run(primarySources, args)
这是整个启动流程最核心、最复杂的方法。
-
执行
getRunListeners方法并调用listeners.starting():- 作用 :获取
SpringApplicationRunListeners并发布ApplicationStartingEvent事件。 - 说明 :
SpringApplicationRunListeners是SpringApplicationRunListener的集合,它专门用于监听SpringApplication的run方法执行过程中的关键节点。第一步就是发布应用正在启动的事件。
- 作用 :获取
-
执行
prepareEnvironment方法:- 作用 :准备和应用环境 (
Environment),这是整个应用配置的基础。 - 最主要的部分是 :
getOrCreateEnvironment():根据应用类型创建StandardEnvironment或StandardServletEnvironment。configureEnvironment(environment, args):配置环境,包括PropertySources(属性源,如 JVM 系统属性、操作系统环境变量)和Profiles(配置文件,如 "dev", "prod")。listeners.environmentPrepared(environment):发布ApplicationEnvironmentPreparedEvent事件。这是一个极其重要的扩展点 ,监听这个事件的监听器(最著名的是ConfigFileApplicationListener)会从application.properties、application.yml等文件中加载我们自定义的配置属性。
- 作用 :准备和应用环境 (
-
执行
printBanner方法:- 作用:在控制台打印 Spring Boot 的 Banner。
-
执行
createApplicationContext方法:- 作用 :创建
ApplicationContext(IoC 容器)。 - 根据第一步推断出的
WebApplicationType,创建不同类型的上下文。对于 Servlet Web 应用,会创建AnnotationConfigServletWebServerApplicationContext。
- 作用 :创建
-
执行
prepareContext方法:- 作用 :准备上面创建好的
ApplicationContext。 - 最主要的部分是 :
postProcessApplicationContext(context):后处理应用上下文,例如设置 Bean 名称生成器、资源加载器。applyInitializers(context):应用初始化器 。调用在第一步中加载的所有ApplicationContextInitializer的initialize方法,允许我们在容器刷新前对上下文进行自定义。listeners.contextPrepared(context):发布ApplicationContextInitializedEvent事件,通知监听器上下文已准备就绪。load(context, sources.toArray(new Object[0])):将主源(即我们的@SpringBootApplication注解类)加载到上下文中,为后续的组件扫描和 Bean 定义注册做准备。listeners.contextLoaded(context):发布ApplicationPreparedEvent事件,通知监听器上下文已加载完毕。
- 作用 :准备上面创建好的
第三阶段:刷新应用上下文 (最最核心)
执行方法:refreshContext(context)
这个方法内部会调用 AbstractApplicationContext.refresh(),这是 Spring 框架容器初始化的标准流程。
-
执行
prepareRefresh()方法:- 作用:刷新前的准备工作,例如初始化属性源、验证必要的属性。
-
执行
obtainFreshBeanFactory()方法:- 作用 :获取或刷新内部的
BeanFactory(DefaultListableBeanFactory)。BeanFactory是 Spring 容器的基础。
- 作用 :获取或刷新内部的
-
执行
prepareBeanFactory(beanFactory)方法:- 作用 :准备
BeanFactory,配置它的类加载器、后置处理器等标准配置。
- 作用 :准备
-
执行
postProcessBeanFactory(beanFactory)方法:- 作用 :允许在 Bean 定义加载完成后、实例化之前,对
BeanFactory进行后处理。这是一个空方法,供子类扩展。
- 作用 :允许在 Bean 定义加载完成后、实例化之前,对
-
执行
invokeBeanFactoryPostProcessors(beanFactory)方法:- 作用 :这是 Spring Boot 自动配置的魔法入口!
- 最主要的部分是 :调用所有
BeanFactoryPostProcessor。 - 其中,
ConfigurationClassPostProcessor会解析@Configuration注解的类。它会发现我们的主类上的@SpringBootApplication注解。 @SpringBootApplication中包含@EnableAutoConfiguration,后者会导入AutoConfigurationImportSelector。AutoConfigurationImportSelector会从META-INF/spring.factories中加载所有EnableAutoConfiguration键对应的自动配置类(如DataSourceAutoConfiguration,WebMvcAutoConfiguration)。- 这些自动配置类根据条件(如类路径下是否存在某个类、是否设置了某个属性等)决定是否生效,并向容器中批量添加 Bean 定义。
-
执行
registerBeanPostProcessors(beanFactory)方法:- 作用 :注册
BeanPostProcessor。这些处理器会在 Bean 实例化之后、初始化前后 被调用,用于对 Bean 进行增强(如@Autowired,@PostConstruct等功能都是通过BeanPostProcessor实现的)。
- 作用 :注册
-
执行
initMessageSource()方法:- 作用:初始化国际化相关的消息源。
-
执行
initApplicationEventMulticaster()方法:- 作用:初始化应用事件广播器,用于事件发布。
-
执行
onRefresh()方法:- 作用 :这是 Spring Boot 创建并启动内嵌 Web 服务器的关键步骤!
- 在
ServletWebServerApplicationContext中,此方法被重写。 - 最主要的部分是
createWebServer()方法 :- 这个方法的作用是 :从
BeanFactory中获取ServletWebServerFactory(如TomcatServletWebServerFactory)。 - 调用
factory.getWebServer(...)方法,这会创建内嵌的 Tomcat/Jetty/Undertow 服务器实例,并初始化 Servlet 容器(初始化DispatcherServlet并注册到容器中)。此时,Web 服务器已经创建好,但尚未开始监听端口。
- 这个方法的作用是 :从
-
执行
registerListeners()方法:- 作用:注册监听器,将事件监听器注册到第 8 步初始化的事件广播器中。
-
执行
finishBeanFactoryInitialization(beanFactory)方法:- 作用 :完成
BeanFactory的初始化,实例化所有剩余的非懒加载单例 Bean。 - 这是 IoC 容器依赖注入发生的主要阶段。我们的 Controller、Service、Repository 等组件都在这个阶段被创建和装配。
- 作用 :完成
-
执行
finishRefresh()方法:- 作用:完成上下文的刷新工作,发布最终事件。
- 最主要的部分是 :
publishEvent(new ContextRefreshedEvent(this)):发布ContextRefreshedEvent事件。- 在
ServletWebServerApplicationContext中,还会调用finishRefresh()的一个扩展,最终启动内嵌的 Web 服务器 (例如TomcatWebServer.start()),开始监听指定的端口。至此,我们的应用已经可以处理 HTTP 请求了。
第四阶段:启动后处理
-
执行
afterRefresh(context, applicationArguments)方法:- 作用:刷新后处理,默认为空。是一个扩展点。
-
执行
listeners.started(context)方法:- 作用 :发布
ApplicationStartedEvent事件,通知所有监听器应用已启动。
- 作用 :发布
-
执行
callRunners(applicationArguments)方法:- 作用 :调用
ApplicationRunner和CommandLineRunner接口的实现类。 - 这是开发者可以在应用启动后、开始接收流量前,执行一些特定初始化逻辑的常用方式。
- 作用 :调用
-
执行
listeners.ready(context, timeTaken)方法:- 作用 :发布
ApplicationReadyEvent事件。这个事件标志着应用已完全启动完毕,处于就绪状态 。它与ApplicationStartedEvent的区别在于,此时所有 Bean 都已初始化,内嵌服务器已在运行。
- 作用 :发布
-
返回
ApplicationContext:- 作用 :将已经完全初始化好的
ApplicationContext返回。
- 作用 :将已经完全初始化好的
总结
整个流程从 main 方法开始,经历了 环境准备 -> 容器创建 -> Bean定义加载(自动配置) -> Bean实例化(依赖注入) -> 内嵌服务器启动 -> 运行自定义初始化逻辑 等一系列复杂而精密的步骤,最终将一个功能完备的 Spring Boot 应用呈现在我们面前。其中 refreshContext() 是整个流程的心脏,而自动配置和内嵌服务器是 Spring Boot 两大核心特性的实现关键。