关于 Spring Boot 的启动流程,其实核心就做两件事:构建对象和运行启动。
我们可以把它想象成“准备开一家餐厅”的过程。以 经典的2.7.6版本为例,主要流程如下:
- 第一阶段:准备工作(new SpringApplication)就像开店前要先确定我们是开火锅店还是奶茶店。
- 确定应用类型:Spring Boot 会自动判断当前是Web 应用(Servlet/MVC)、响应式应用(Reactive)还是普通应用(Non-Web Application)。
- 加载初始化器和监听器:利用 SPI 机制(读取 spring.factories),把所有需要用到的初始化器和监听器都找出来存好,随时待命。
- 第二阶段:正式启动(run 方法) 这是最核心的阶段,就像点火开业,主要分五步走:
- 准备环境(Environment):先把配置文件 application.yml、环境变量、命令行参数都加载好,组成一个环境对象。
- 创建容器(ApplicationContext):根据第一步确定的类型,创建一个空的 Spring IOC 容器(比如 AnnotationConfigServletWebServerApplicationContext)。
- 刷新容器(Refresh Context),这是最重要的一步。Spring 会解析@SpringBootApplication),扫描所有的 Bean,执行自动配置(AutoConfiguration),把所有组件注入到容器里。关键点:如果是 Web 应用,内嵌的 Tomcat 就是在这个环节(
onRefresh方法)启动的。 - 收尾工作:容器刷新完成后,发布启动完成事件,通知所有监听器。
- 执行回调(Runners):最后,检查有没有实现了
CommandLineRunner或ApplicationRunner的 Bean,如果有,就执行它们的run方法。这通常是我们写开机自启任务的地方。

三种Spring应用对比
| 类型 | 本质 |
|---|---|
| 普通应用 | 一个 Java 程序,main 方法启动,干完活就结束 |
| Web 应用(Servlet) | 基于 线程阻塞模型 的 HTTP 服务 |
| 响应式应用(Reactive) | 基于 事件驱动 + 非阻塞 的 HTTP 服务 |
详细分析SpringBoot启动流程
启动入口:main()方法
Spring Boot 应用的启动从包含@SpringBootApplication注解的main()方法开始。@SpringBootApplication是一个组合注解,包含了以下三个核心注解:
@SpringBootConfiguration相当于@Configuration表示该类是 Spring 配置类。@EnableAutoConfiguration:启用自动配置功能。@ComponentScan启用组件扫描,默认扫描当前包及其子包下的 Spring 组件(如@Service@Controller@Repository等)。
@SpringBootConfiguration本质上是一个组合注解,它内部标注了@Configuration,因此在功能上与@Configuration等价。
不同的是,@SpringBootConfiguration是 Spring Boot 专用注解,用于标识 应用的主配置类,Spring Boot 在启动过程中会对该注解进行特殊识别,以确定自动配置、生效范围以及组件扫描的基准包,从而增强语义表达并避免配置类的混淆。
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
会触发
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
创建 SpringApplication 实例
SpringApplication 是 Spring Boot 启动的核心类,它负责引|导整个 Spring 应用的启动流程。在 run() 方法中,会创建SpringApplication 对象,并根据类路径中的依赖和配置进行初始化。
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//推断应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
//设置初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 设置启动监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 确定主应用类
this.mainApplicationClass = deduceMainApplicationClass();
}
推断应用类型:Spring Boot 会根据类路径中的依赖自动判断应用是 Web 应用、Reactive 应用还是普通的非 Web 应用。常见的应用类型包括:
- Servlet 应用:如果类路径中存在
javax.servlet.Servlet。 - Reactive 应用:如果类路径中存在
org.springframework.web.reactive.DispatcherHandler - None 类型:不包含 Web 服务器,仅适用于普通的非 Web 应用。
run()方法详解
创建完 SpringApplication 后,SpringBoot 启动后续所有逻辑都在这个 run 方法里面。这个方法也是 Spring Boot 应用的核心启动流程,它负责启动应用、初始化上下文、执行各种初始化逻辑,并通知相关的监听器和组件。
public ConfigurableApplicationContext run(String... args) {
// 1.启动时间记录: 通过System.nanoTime()记录应用启动的时间,用于统计整个启动过程的耗时。
long startTime = System.nanoTime();
// 2. 创建 DefaultBootstrapContext,用于在启动过程中保存共享的对象上下文,提供基础的启动支持
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 3.配置系统属性 "java.awt.headless",适用于没有显示器的服务器环境
configureHeadlessProperty();
// 4. 获取 SpringApplicationRunListeners,这些监听器可以监听应用的启动过程, 监听应用的各个生命周期事件。
SpringApplicationRunListeners listeners = getRunListeners(args);
// 5. 通知所有监听器,Spring Boot 应用程序即将启动
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 6. 解析传入的命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 7. 准备环境,加载配置文件、环境变量、命令行参数等
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 8. 配置环境,决定是否忽略 Java 的 `BeanInfo` 类,以加快启动速度
configureIgnoreBeanInfo(environment);
// 9. 打印 Banner(欢迎信息),通常会在控制台或日志中展示
Banner printedBanner = printBanner(environment);
// 10. 创建应用上下文(ApplicationContext),可以是不同类型的 Web 或非 Web 上下文
context = createApplicationContext();
// 11.设置应用启动监控器,用于收集应用启动过程中的统计数据
context.setApplicationStartup(this.applicationStartup);
// 12.准备应用上下文,注入环境、事件监听器、命令行参数等
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 13.刷新上下文,启动 Spring 的核心容器,完成 Bean 的初始化等过程,其间会触发内嵌的 web 容器
refreshContext(context);
// 14.上下文刷新后的回调操作,可以用于自定义初始化逻辑
afterRefresh(context, applicationArguments);
// 15.计算应用启动耗时
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
// 16.如果配置了日志,输出启动耗时等信息
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
// 17.通知监听器,应用上下文已启动完成
listeners.started(context, timeTakenToStartup);
// 18.执行 CommandLineRunner 或 ApplicationRunner 接口中的代码
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
// 19.处理启动过程中发生的异常
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
// 20.计算到应用完全准备好所需的时间
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
// 21.通知监听器,应用已经完全准备好
listeners.ready(context, timeTakenToReady);
}
catch (Throwable ex) {
// 22.处理应用准备过程中的异常
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
// 23.返回创建好的应用上下文
return context;
}
启动监听器
启动监听器 ApplicationListener在 Spring Boot 启动过程中起到监听特定事件的作用。Spring Boot 中的事件机制会触发不同的生命周事件,比如:
ApplicationStartingEvent:在应用启动时触发。ApplicationEnvironmentPreparedEvent:在环境变量和配置文件准备完成时触发。ApplicationPreparedEvent:在 Spring 容器(ApplicationContext)准备完成时触发。
这些事件都可以通过ApplicationListener进行监听,使得可以在应用启动过程中进行自定义处理。
准备环境 ConfigurableEnvironment
在启动过程中,Spring Boot 通过 configurableEnvironment 准备应用的环境变量。它会读取配置文件(如 application.properties或 application.yml ),并加载系统环境变量、命令行参数等。Spring Boot 使用PropertySource 来管理这些配置属性。
激活配置文件:Spring Boot 支持通过spring.profiles.active配置信息 激活不同的配置文件,以实现开发、测试、生产环境的灵活切换。
创建 ApplicationContext
创建 ApplicationContext,会注册所有配置类和自动配置类Spring Boot 使用@EnableAutoConfiguration自动加载符合条件的配置类。自动配置机制基于条件注解(如@Conditional0nClass @ConditionalOnMissingBean等),在满足条件时自动注入相应的 Bean (自动装配)。
- 加载配置类:包括开发者定义的
@Configuration类以及 Spring Boot 提供的自动配置类(如DataSourceAutoConfigurationWebMvcAutoConfiguration等)。 - 注册 BeanPostProcessor :Spring 的 Bean 生命周期会经过
BeanPostProcessor的处, 这些包括依赖注入,AOP代理等操作。
刷新 ApplicationContext
它负责完成以下工作:
- 创建并初始化所有单例 Bean: Spring 容器会创建并初始化所有定义的单例 Bean。这里包括开发者定义的 Bean 以及自动配置注入的 Bean。
- 处理 BeanPostProcessor:在 Bean 初始化之前和之后,Spring 通过 BeanPostProcessor 对 Bean 进行加工,例如为某些 Bean 创建 AOP 代理对象。
- 事件发布与监听:在容器刷新过程中,Spring 会发布ContextRefreshedEvent,通知监听器应用上下文刷新完成。
启动嵌入式 Web服务器 (如 Tomcat)
对于 Web 应用,Spring Boot 会自动启动嵌入式 Web 服务器(默认是Tomcat)。这一步是在刷新refresh()方法的最后阶段进行的,主要包括以下操作:
- 注册内置的 Servlet 和 Filter: Spring Boot 会自动注册
DispatcherServletErrorPageFilter等 Servlet 和 Filter。 - 启动嵌入式 Web 容器:Spring Boot 根据应用的类型自动选择 Web 容器,并绑定到指定的端口上监听 HTTP 请求。
执行 CommandLineRunner 和 ApplicationRunner
Spring Boot 在应用启动完成后,会调用实现了CommandLineRunner``或ApplicationRunner 接口的 Bean。这两个接口适合在应用启动后执行一些初始化逻辑。
@Component
public class MyStartupRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("^_^");
}
}