Spring Boot 的启动流程核心是 "自动配置 + 容器初始化 + 应用就绪" ,通过封装 Spring 框架的繁琐配置,实现 "一键启动"。整个流程可拆解为 3 大阶段、10 个关键步骤,从入口类执行到 Web 服务启动,每一步都围绕 "简化配置、快速部署" 的核心目标,下面结合源码逻辑和实际场景详细拆解:
一、启动流程总览(核心 3 阶段)
准备阶段(初始化环境/参数)→ 初始化阶段(创建容器/自动配置)→ 运行阶段(启动Web服务/应用就绪)
- 准备阶段:解析启动参数、初始化环境(配置文件、系统变量)、创建启动器;
- 初始化阶段:创建 Spring 容器(ApplicationContext)、执行自动配置、扫描并注册 Bean;
- 运行阶段:启动嵌入式 Web 服务器(如 Tomcat)、发布容器就绪事件、应用进入运行状态。
二、详细启动步骤(结合源码 + 示例)
前提:启动类基础结构
Spring Boot 启动的入口是 标注 @SpringBootApplication 的主类 ,核心是 SpringApplication.run(...) 方法,示例:
typescript
@SpringBootApplication // 核心注解(包含3个关键注解)
public class SpringBootDemoApplication {
public static void main(String[] args) {
// 启动入口:返回 Spring 应用上下文(ApplicationContext)
ConfigurableApplicationContext context = SpringApplication.run(SpringBootDemoApplication.class, args);
}
}
@SpringBootApplication 是复合注解,包含 3 个核心注解(启动流程的基础):
@SpringBootConfiguration:标记当前类为配置类(等价于@Configuration);@ComponentScan:扫描当前包及子包下的@Component、@Service、@Controller等 Bean;@EnableAutoConfiguration:开启自动配置(核心!通过SpringFactoriesLoader加载自动配置类)。
步骤 1:执行 SpringApplication.run(...) 方法(入口)
SpringApplication.run(...) 是启动的核心入口,本质是 创建 SpringApplication 实例 + 调用 run() 方法,源码简化:
typescript
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
// 1. 创建 SpringApplication 实例(初始化启动器、监听器等)
return new SpringApplication(primarySources).run(args);
}
这一步会先初始化 SpringApplication 实例,再执行其 run() 方法(真正的启动逻辑)。
步骤 2:初始化 SpringApplication 实例(准备阶段)
SpringApplication 构造函数的核心工作是 初始化启动上下文信息,包括:
- 设置主要源(Primary Sources) :记录启动类(如
SpringBootDemoApplication.class),后续用于扫描配置; - 判断应用类型 :通过
ClassUtils检测当前环境是否存在Servlet、Reactive相关类,自动判断应用类型(默认ServletWebApplicationType,即传统 Web 应用); - 加载应用监听器(ApplicationListener) :通过
SpringFactoriesLoader加载META-INF/spring.factories中配置的所有ApplicationListener(用于监听启动过程中的事件,如容器初始化完成、Web 服务器启动等); - 设置应用入口类 :通过栈追踪找到
main方法所在的类(即启动类)。
源码简化:
scss
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 判断应用类型
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 加载初始化器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 加载监听器
this.mainApplicationClass = deduceMainApplicationClass(); // 推导入口类
}
步骤 3:执行 SpringApplication.run(args) 核心逻辑(初始化阶段)
SpringApplication 的 run() 方法是启动流程的核心,包含 "环境准备、容器创建、自动配置、Bean 注册" 等关键操作,源码简化后的流程:
scss
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch(); // 计时工具(记录启动耗时)
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty(); // 配置无头模式(默认 true,用于服务器环境)
// 1. 加载 SpringApplicationRunListener(启动监听器,监听启动全流程)
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(); // 发布「启动开始」事件(starting)
try {
// 2. 准备应用参数(封装命令行参数 args)
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 3. 准备环境(核心!加载配置文件、系统变量、命令行参数)
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment); // 配置忽略 Bean 信息
// 4. 打印 Banner(启动时的 Spring 图标,可自定义)
Banner printedBanner = printBanner(environment);
// 5. 创建 Spring 应用上下文(ApplicationContext)
context = createApplicationContext();
// 6. 加载异常报告器(用于启动失败时输出详细异常信息)
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 7. 准备上下文(核心!关联环境、注册 Bean、执行自动配置)
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 8. 刷新上下文(核心!Spring 容器初始化的核心方法,触发 Bean 实例化、依赖注入、初始化)
refreshContext(context);
// 9. 刷新后的操作(空实现,供用户扩展)
afterRefresh(context, applicationArguments);
stopWatch.stop(); // 停止计时
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context); // 发布「容器启动完成」事件(started)
// 10. 执行所有 CommandLineRunner 和 ApplicationRunner 接口实现类
callRunners(context, applicationArguments);
} catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context); // 发布「应用运行中」事件(running)
} catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context; // 返回初始化完成的容器
}
下面重点拆解 run() 方法中的 核心子步骤(步骤 3-8 是关键):
子步骤 3.1:准备环境(prepareEnvironment)
核心目标:整合所有配置源,生成统一的环境对象(ConfigurableEnvironment) ,配置源优先级从高到低:
- 命令行参数(
args); - 系统环境变量(如
JAVA_HOME); - 操作系统环境变量;
- 配置文件(
application.properties/application.yml,按位置:命令行指定 → 项目根目录 →classpath:/config/→classpath:/); - 默认配置(Spring 内置默认值)。
关键操作:
- 加载配置文件:根据环境(
spring.profiles.active)加载对应的配置(如application-dev.yml); - 发布事件:通过
listeners.environmentPrepared(environment)发布「环境准备完成」事件,供监听器处理(如配置解密、自定义配置加载)。
子步骤 3.2:创建应用上下文(createApplicationContext)
根据步骤 2 判断的 webApplicationType(应用类型),创建对应的 ApplicationContext(Spring 容器):
- 传统 Web 应用(
ServletWebApplicationType):创建AnnotationConfigServletWebServerApplicationContext; - 响应式 Web 应用(
ReactiveWebApplicationType):创建AnnotationConfigReactiveWebServerApplicationContext; - 非 Web 应用(
NoneWebApplicationType):创建AnnotationConfigApplicationContext。
ApplicationContext 是 Spring 的核心容器,负责管理 Bean 的生命周期(实例化、依赖注入、初始化、销毁)。
子步骤 3.3:准备上下文(prepareContext)
核心目标:将环境、启动类、监听器等关联到容器,为刷新容器做准备,关键操作:
- 给容器设置环境(
context.setEnvironment(environment)); - 执行容器初始化器(
ApplicationContextInitializer):通过SpringFactoriesLoader加载的初始化器,对容器进行自定义初始化(如设置资源加载器、添加属性源); - 发布「上下文准备完成」事件(
contextPrepared); - 注册启动类为 Bean:将启动类(
primarySources)注册到容器中(作为配置类,后续扫描@Bean注解); - 发布「上下文加载完成」事件(
contextLoaded)。
子步骤 3.4:刷新上下文(refreshContext)→ 容器初始化核心
refreshContext 最终调用 ApplicationContext.refresh() 方法(Spring 框架的核心方法),这是 Bean 生命周期的触发点,关键操作包括:
- 初始化容器的 BeanFactory(
ConfigurableListableBeanFactory); - 执行 BeanFactory 后置处理器(
BeanFactoryPostProcessor):修改 Bean 定义(如自动配置类的 Bean 注册); - 注册 Bean 后置处理器(
BeanPostProcessor):用于 Bean 初始化前后的增强(如 AOP 代理、@PostConstruct注解解析); - 初始化消息源(国际化支持);
- 初始化事件多播器(用于事件发布 / 订阅);
- 初始化 Web 服务器(嵌入式 Tomcat/Jetty/Undertow):这是 Spring Boot 无需外部服务器的核心 ------ 通过
ServletWebServerFactory自动创建并启动 Web 服务器; - 注册剩余的单例 Bean:扫描
@Component、@Service等注解的 Bean,执行实例化、属性填充、初始化(对应 Spring Bean 生命周期的核心阶段); - 完成容器刷新:发布「容器刷新完成」事件(
ContextRefreshedEvent)。
关键说明 :嵌入式 Web 服务器的启动是在此步骤完成的 ------Spring Boot 自动配置类(如 TomcatServletWebServerFactoryAutoConfiguration)会注册 ServletWebServerFactory Bean,刷新容器时会调用其 getWebServer() 方法创建并启动 Web 服务器。
步骤 4:执行 CommandLineRunner 和 ApplicationRunner(运行阶段)
容器刷新完成后,Spring Boot 会自动扫描并执行所有实现 CommandLineRunner 或 ApplicationRunner 接口的 Bean------ 这是开发者在应用启动后执行自定义逻辑(如数据预热、缓存初始化、接口调用)的常用扩展点。
CommandLineRunner:接收原始命令行参数(String[] args);ApplicationRunner:接收封装后的应用参数(ApplicationArguments,支持解析选项参数,如--name=test)。
执行顺序:可通过 @Order 注解指定(value 越小,执行越早)。
示例:
java
@Component
@Order(1)
public class MyCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("【CommandLineRunner】应用启动后执行:参数=" + Arrays.toString(args));
}
}
@Component
@Order(2)
public class MyApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("【ApplicationRunner】应用启动后执行:选项参数=" + args.getOptionNames());
}
}
步骤 5:发布「应用运行中」事件(running)
所有启动流程完成后,通过 listeners.running(context) 发布 ApplicationReadyEvent 事件,标识应用已完全就绪,可处理外部请求。
三、核心扩展点(开发者常用)
Spring Boot 启动流程提供了多个扩展点,允许开发者干预启动过程,常用的有:
ApplicationContextInitializer:容器初始化前执行,用于修改容器配置(如添加属性源、设置环境变量);ApplicationListener:监听启动过程中的事件(如starting、environmentPrepared、started、running),执行自定义逻辑;CommandLineRunner/ApplicationRunner:应用启动后执行,用于数据预热、初始化任务;BeanPostProcessor:Bean 初始化前后增强(如 AOP 代理、属性校验);- 自动配置排除 / 自定义 :通过
@SpringBootApplication(exclude = XXXAutoConfiguration.class)排除不需要的自动配置类,或通过@Configuration自定义配置覆盖默认自动配置。
四、启动流程关键总结
- 核心驱动 :
SpringApplication.run(...)是入口,ApplicationContext.refresh()是容器初始化核心; - 自动配置核心 :
@EnableAutoConfiguration+SpringFactoriesLoader加载META-INF/spring.factories中的自动配置类; - Web 服务器启动 :嵌入式服务器(Tomcat)在
refreshContext阶段通过自动配置类启动,无需外部部署; - 扩展灵活 :通过
CommandLineRunner、ApplicationListener等扩展点,可轻松添加自定义逻辑; - 配置优先级:命令行参数 > 系统环境变量 > 配置文件 > 默认配置。
五、常见问题与优化
- 启动慢 :检查自动配置类(是否加载过多无用配置,可通过
exclude排除)、Bean 数量(减少不必要的 Bean 扫描)、初始化任务(如CommandLineRunner中是否有耗时操作); - 配置不生效 :检查配置文件路径(是否在
classpath:/或classpath:/config/下)、配置优先级(是否被命令行参数覆盖)、spring.profiles.active是否正确激活; - Web 服务器启动失败 :检查端口是否被占用(修改
server.port)、是否冲突依赖(如同时引入 Tomcat 和 Jetty 依赖)。
总结
Spring Boot 的启动流程本质是 "封装 Spring 容器初始化流程 + 自动配置 + 嵌入式服务器启动" ,通过简化配置、自动整合依赖,实现 "开箱即用"。核心步骤可概括为:入口类执行 → 初始化 SpringApplication → 准备环境/参数 → 创建容器 → 刷新容器(Bean 初始化 + 服务器启动)→ 执行启动后任务 → 应用就绪。
理解启动流程有助于:
- 排查启动故障(如配置不生效、Bean 注册失败、服务器启动失败);
- 灵活使用扩展点(如启动后初始化、自定义配置);
- 优化启动性能(排除无用自动配置、减少 Bean 扫描范围)。