基于 SpringBoot 2.4.4 源码 + 真实运行日志验证。整体分 5 个阶段:构造 → 启动准备 → 准备 ApplicationContext → 刷新 → 启动完成。每阶段标注扩展点(🔌)和日志验证(✅)。
缩写速查:Spring 术语与缩写速查 · 相关笔记:Spring 容器启动流程源码分析 · Spring 三级缓存与循环依赖
目录
| 章节 | 说明 |
|---|---|
| 流程总览 | 5 阶段结构图 |
| 阶段一:构造 SpringApplication | WebType 推断、三大组件加载 |
| 阶段二:run() 启动准备 | 事件、Environment、配置文件加载 |
| 阶段三:准备 ApplicationContext | 创建上下文、BeanDefinition 加载 |
| 阶段四:刷新 ApplicationContext | Spring IOC 核心、Tomcat 启动 |
| 阶段五:启动完成 | Runner 回调、就绪事件 |
| 扩展点汇总 | 所有扩展点一览(含典型实现类) |
| BeanFactory 创建时机与 BeanDefinition 两步加载 | BeanFactory 何时创建、种子 BD 如何被展开 |
流程总览
SpringApplication.run(primarySources, args)
│
├─ 阶段一:new SpringApplication
│ 推断 WebType → 加载 Bootstrapper / Initializer / Listener
│
├─ 阶段二:instance.run(args)
│ BootstrapContext → starting 事件 → prepareEnvironment → Banner
│
├─ 阶段三:prepareContext
│ createApplicationContext → applyInitializers → load BeanDefinition
│
├─ 阶段四:refreshContext
│ ShutdownHook → Spring refresh(BFPP → BPP → Bean 实例化 → Tomcat 启动)
│
└─ 阶段五:启动完成
afterRefresh → started 事件 → Runners → ready 事件
阶段一:构造 SpringApplication
入口等同于 new SpringApplication(primarySources).run(args),构造阶段完成 4 件事:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 1. 推断 WebApplicationType(检测类路径)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 2-4. 通过 spring.factories 加载三大组件
this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 5. 堆栈回溯找到 main() 所在类
this.mainApplicationClass = deduceMainApplicationClass();
}
1.1 WebApplicationType 推断
| 检测条件 | 结果 |
|---|---|
类路径存在 DispatcherHandler,不存在 DispatcherServlet |
REACTIVE |
类路径存在 Servlet + ConfigurableWebApplicationContext |
SERVLET |
| 其他 | NONE |
1.2 Bootstrapper
作用:refresh 前的轻量辅助容器,用于注册创建代价高或需要早期共享的实例。以 Class 为 key,每类型只能存一个。
生命周期:prepareContext 阶段调用 bootstrapContext.close(context) 后关闭,非用户扩展 API。
1.3 ApplicationContextInitializer 🔌
作用:在 refresh() 前回调,典型用途是注册额外的 PropertySource 或激活 Profile。
默认加载的 5 个实现(spring.factories):
| 实现类 | 功能 |
|---|---|
ConfigurationWarningsApplicationContextInitializer |
检测问题扫描路径(如 org.springframework),打印警告 |
ContextIdApplicationContextInitializer |
设置上下文 ContextId |
DelegatingApplicationContextInitializer |
读取 context.initializer.classes 属性加载自定义 Initializer |
RSocketPortInfoApplicationContextInitializer |
将 RSocket Server 端口写入 server.ports |
ServerPortInfoApplicationContextInitializer |
将 Web Server 端口写入 server.ports |
自定义注册方式:①
spring.factories写入;②context.initializer.classes属性配置。
1.4 ApplicationListener 🔌
作用:观察者模式,监听生命周期事件。默认加载 8 个监听器:
| 监听器 | 监听事件 | 功能 |
|---|---|---|
ClearCachesApplicationListener |
ContextRefreshedEvent |
清空反射缓存、ClassLoader 缓存 |
ParentContextCloserApplicationListener |
ParentContextAvailableEvent |
父上下文关闭时联动关闭子上下文 |
FileEncodingApplicationListener |
EnvironmentPreparedEvent |
校验 file.encoding 一致性 |
AnsiOutputApplicationListener |
EnvironmentPreparedEvent |
设置 ANSI 输出 |
DelegatingApplicationListener |
EnvironmentPreparedEvent |
读取 context.listener.classes 加载自定义监听器 |
LoggingApplicationListener |
Starting/Prepared/Closed/Failed | 联动 LoggingSystem 生命周期 |
EnvironmentPostProcessorApplicationListener |
EnvironmentPreparedEvent |
触发配置文件加载(入口) |
LiquibaseServiceLocatorApplicationListener |
ApplicationStartingEvent |
Liquibase 初始化 |
阶段二:run() 启动准备
2.1 基础准备
StopWatch stopWatch = new StopWatch();
stopWatch.start();
DefaultBootstrapContext bootstrapContext = createBootstrapContext(); // 初始化 Bootstrapper
configureHeadlessProperty(); // java.awt.headless=true,服务器无图形界面
2.2 发布 ApplicationStartingEvent
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
// → LoggingApplicationListener 响应:初始化 LoggingSystem
// → LiquibaseServiceLocatorApplicationListener 响应
2.3 prepareEnvironment(配置加载核心)✅ 日志验证
调用链(日志验证顺序):
listeners.environmentPrepared()
→ EnvironmentPostProcessorApplicationListener
→ RandomValuePropertySource 加入 ✅
→ ConfigDataEnvironmentPostProcessor ✅
→ ConfigDataEnvironment(构建属性源贡献者)✅
→ 扫描配置文件位置(见下表)
→ 加载 application.yaml ✅
StandardServletEnvironment 默认属性源(✅ 日志验证):
| 属性源 | 内容 |
|---|---|
systemProperties |
JVM 系统属性 |
systemEnvironment |
OS 环境变量 |
servletContextInitParams |
ServletContext 初始化参数 ✅ |
servletConfigInitParams |
ServletConfig 初始化参数 ✅ |
configurationProperties |
Spring 配置属性绑定 ✅ |
配置文件扫描位置(优先级从高到低,file 系列高于 classpath)✅ 日志验证:
① file:./config/*/
② file:./config/
③ file:./
④ classpath:/config/
⑤ classpath:/ ← application.yaml 从此处加载 ✅
扩展点:自定义 EnvironmentPostProcessor 🔌
// spring.factories 注册
org.springframework.boot.env.EnvironmentPostProcessor=com.example.MyEnvPostProcessor
public class MyEnvPostProcessor implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment env, SpringApplication app) {
// 可新增/修改属性源,优先级高于 application.properties
env.getPropertySources().addFirst(new MapPropertySource("custom", Map.of("key", "value")));
}
}
阶段三:准备 ApplicationContext
3.1 createApplicationContext ✅ 日志验证
// 按 WebType 创建对应实现(✅ 日志:Refreshing AnnotationConfigServletWebServerApplicationContext)
switch (webApplicationType) {
case SERVLET: return new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE: return new AnnotationConfigReactiveWebServerApplicationContext();
default: return new AnnotationConfigApplicationContext();
}
3.2 prepareContext 执行顺序
context.setEnvironment(environment); // 将 Environment 注入上下文
postProcessApplicationContext(context); // 注册 ConversionService / ResourceLoader
applyInitializers(context); // 🔌 回调所有 ApplicationContextInitializer
listeners.contextPrepared(context); // 发布 ContextPreparedEvent
bootstrapContext.close(context); // 辅助容器关闭
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
load(context, sources.toArray(...)); // 🔌 加载 BeanDefinition(自动装配入口)
listeners.contextLoaded(context); // 发布 ContextLoadedEvent
3.3 自动装配入口(load 阶段)🔌
load(启动类)
→ 解析 @SpringBootApplication
→ @EnableAutoConfiguration
→ AutoConfigurationImportSelector
→ spring.factories: org.springframework.boot.autoconfigure.EnableAutoConfiguration
→ 按 @Conditional 条件筛选后注册 BeanDefinition
阶段四:刷新 ApplicationContext
4.1 注册 ShutdownHook
context.registerShutdownHook(); // 进程退出时触发 context.close(),Bean 优雅销毁
refresh((ApplicationContext) context);
4.2 AbstractApplicationContext#refresh() ✅ 日志验证
SpringBoot 委托给 Spring Core 的标准刷新流程,6 个关键步骤:
| 步骤 | 方法 | 说明 |
|---|---|---|
| ① | prepareRefresh() |
上下文状态设置,initPropertySources |
| ② | invokeBeanFactoryPostProcessors() 🔌 |
ConfigurationClassPostProcessor 解析 @Configuration,OnClassCondition 批量判断 AutoConfiguration ✅ |
| ③ | registerBeanPostProcessors() 🔌 |
注册 AOP / 事务 BeanPostProcessor |
| ④ | finishBeanFactoryInitialization() |
实例化所有非懒加载 Bean,执行 @Autowired / @PostConstruct |
| ⑤ | onRefresh() |
启动内嵌 Tomcat/Netty ✅,注册 Servlet/Filter |
| ⑥ | publishEvent(ContextRefreshedEvent) |
触发 ClearCachesApplicationListener 清空缓存 |
关键顺序:Tomcat 在
onRefresh()启动,晚于 Bean 实例化(④),保证所有 Bean 就绪后才开放端口。✅ 日志验证:Root WebApplicationContext: initialization completed→Tomcat started on port(s): 9999
阶段五:启动完成
afterRefresh(context, applicationArguments); // 🔌 空实现,可覆写
stopWatch.stop();
listeners.started(context); // 发布 ApplicationStartedEvent
callRunners(context, applicationArguments); // 🔌 回调 Runner
listeners.running(context); // 发布 ApplicationReadyEvent(服务就绪)
Runner 执行顺序 🔌
// 两类 Runner 按 @Order 混合排序后依次执行
// ApplicationRunner:封装了 ApplicationArguments(支持 --key=value 解析)
// CommandLineRunner:直接传原始 String[] args
@Component
@Order(1)
public class MyRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
// 上下文已完全就绪,可安全使用所有 Bean
// 典型用途:数据预热、缓存初始化、健康检查
}
}
扩展点汇总
| 扩展点 | 注册方式 | 触发时机 | 典型实现类 | 典型用途 |
|---|---|---|---|---|
BootstrapRegistryInitializer |
spring.factories |
createBootstrapContext() |
自定义实现 | refresh 前注册早期共享实例(如远程配置中心连接) |
ApplicationListener |
spring.factories / context.listener.classes |
各生命周期事件 | LoggingApplicationListenerEnvironmentPostProcessorApplicationListenerClearCachesApplicationListener |
监听启动/停止事件 |
ApplicationContextInitializer |
spring.factories / context.initializer.classes |
refresh 前 | ConfigurationWarningsApplicationContextInitializerServerPortInfoApplicationContextInitializerContextIdApplicationContextInitializer |
注册 PropertySource、激活 Profile |
EnvironmentPostProcessor |
spring.factories |
EnvironmentPreparedEvent |
ConfigDataEnvironmentPostProcessor(加载 application.yaml)RandomValuePropertySourceEnvironmentPostProcessor |
加密配置解密、外部配置中心 |
BeanDefinitionRegistryPostProcessor |
@Component / @Bean / spring.factories |
invokeBeanFactoryPostProcessors 最先执行 |
ConfigurationClassPostProcessor(解析 @Configuration / @ComponentScan / @Import) |
注册额外 BeanDefinition |
BeanFactoryPostProcessor |
@Component / @Bean |
invokeBeanFactoryPostProcessors |
PropertySourcesPlaceholderConfigurer(解析 ${...})EventListenerMethodProcessor |
修改已有 BeanDefinition |
BeanPostProcessor |
@Component / @Bean |
Bean 实例化前后 | AutowiredAnnotationBeanPostProcessor(@Autowired)CommonAnnotationBeanPostProcessor(@Resource/@PostConstruct)AbstractAutoProxyCreator(AOP 代理) |
AOP 代理、属性注入 |
ApplicationRunner |
@Component |
所有 Bean 就绪后 | 自定义实现 | 数据预热、缓存初始化 |
CommandLineRunner |
@Component |
所有 Bean 就绪后 | 自定义实现 | 同上,args 格式不同 |
afterRefresh 覆写 |
继承 SpringApplication |
refresh 完成后 | 自定义实现 | 极少用,Runner 优先 |
AutoConfiguration |
spring.factories |
invokeBeanFactoryPostProcessors 中展开 |
DataSourceAutoConfigurationWebMvcAutoConfigurationJacksonAutoConfiguration |
框架自动装配 |
BeanFactory 创建时机与 BeanDefinition 两步加载
BeanFactory 在哪里创建
BeanFactory 在 prepareContext 之前就已构建完毕,创建时机是 createApplicationContext():
// SpringApplication#run()
context = createApplicationContext(); // ① BeanFactory 在此创建(空)
prepareContext(..., context, ...); // ② 往 BeanFactory 注册"种子" BeanDefinition
refreshContext(context); // ③ refresh() 展开所有 BeanDefinition
createApplicationContext() 根据 WebApplicationType 选择实现类,其构造器里:
// AnnotationConfigServletWebServerApplicationContext 构造器
public AnnotationConfigServletWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this); // 注册注解处理器 BD
this.scanner = new ClassPathBeanDefinitionScanner(this); // 准备组件扫描器
// 父类 GenericApplicationContext 构造器:
// this.beanFactory = new DefaultListableBeanFactory(); ← 空 BeanFactory 就绪
}
BeanDefinition 两步加载
Spring Boot 的 BeanDefinition 加载分两步完成,核心桥梁是 ConfigurationClassPostProcessor:
第一步(prepareContext → load()):注册"种子"
BeanDefinitionLoader 将 sources 注册为 BeanDefinition,sources 来源包括:
| 来源 | 说明 |
|---|---|
SpringApplication.run(Application.class, args) 传入的启动类 |
最常见,1 个 @SpringBootApplication BD |
new SpringApplication(A.class, B.class) 额外传入的类 |
多个入口类 |
SpringApplicationBuilder.sources("classpath:extra.xml") |
XML 配置文件 |
ApplicationContextInitializer#initialize() 直接注册 |
极少,通常在 Initializer 里操作 |
此阶段只把 Application.class 注册为一个 BD,其上的 @ComponentScan / @Import 尚未展开。
第二步(refreshContext → invokeBeanFactoryPostProcessors):展开所有 BD
ConfigurationClassPostProcessor(实现 BeanDefinitionRegistryPostProcessor)拿到第一步的种子 BD,递归解析:
ConfigurationClassPostProcessor#processConfigBeanDefinitions()
└── 解析 @SpringBootApplication
├── @ComponentScan → 扫描所有 @Component/@Service/@Repository
├── @EnableAutoConfiguration
│ └── AutoConfigurationImportSelector
│ └── spring.factories → 按 @Conditional 筛选 → 注册 AutoConfig BD
└── @Bean 方法 → 注册方法级 BeanDefinition
完整时序:
createApplicationContext() BeanFactory 创建(空)
↓
prepareContext → load(sources) 注册 Application.class BD(1个种子)
↓
refresh → invokeBFPP
└── ConfigurationClassPostProcessor 展开 @ComponentScan / @Import / @Bean
BeanFactory 中 N 个 BD 全部就绪
↓
finishBeanFactoryInitialization() 实例化所有非懒加载 Bean
关键结论:
prepareContext阶段 BeanFactory 已存在,但只有"种子";真正的业务 Bean、AutoConfiguration Bean 全部由ConfigurationClassPostProcessor在refresh()内完成注册。这就是 Spring Boot 自动装配与 Spring 容器 refresh 流程的衔接点。
参考资料
- Spring Boot 官方文档 — Application Events and Listeners
- Spring Framework — AbstractApplicationContext#refresh
- 运行日志验证环境:SpringBoot 2.4.4 + Java 17,
-Dlogging.level.org.springframework.boot=TRACE
评论 (0)
发表评论