Spring Boot 启动流程
2025/12/28大约 6 分钟约 1805 字
Spring Boot 启动流程

1. 启动入口
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}2. 启动流程概览
┌─────────────────────────────────────────────────────────────────┐
│ 阶段一:准备阶段 │
│ 创建 SpringApplication 对象 │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 阶段二:创建容器 │
│ 创建 ApplicationContext │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 阶段三:刷新容器 refresh()(核心!) │
│ 解析配置 → 自动装配 → 实例化 Bean │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 阶段四:启动完成 │
│ 执行 Runner → 发布事件 │
└─────────────────────────────────────────────────────────────────┘3. 阶段一:准备阶段
3.1 创建 SpringApplication 对象
public SpringApplication(Class<?>... primarySources) {
// 1. 推断 Web 应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 2. 加载 ApplicationContextInitializer
setInitializers(getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 3. 加载 ApplicationListener
setListeners(getSpringFactoriesInstances(ApplicationListener.class));
// 4. 推断主启动类
this.mainApplicationClass = deduceMainApplicationClass();
}3.2 Web 应用类型
| 类型 | 条件 |
|---|---|
| SERVLET | 类路径有 Servlet 相关类 |
| REACTIVE | 类路径有 WebFlux 相关类 |
| NONE | 普通 Java 应用 |
3.3 从 spring.factories 加载
ApplicationContextInitializer:容器初始化器ApplicationListener:应用监听器
4. 阶段二:创建容器
4.1 run() 方法流程
public ConfigurableApplicationContext run(String... args) {
// 1. 创建启动监听器
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
// 2. 准备环境(加载配置文件)
ConfigurableEnvironment environment = prepareEnvironment(listeners, args);
// 3. 打印 Banner
printBanner(environment);
// 4. 创建 ApplicationContext
context = createApplicationContext();
// 5. 准备 Context
prepareContext(context, environment, listeners, args);
// 6. 刷新 Context(核心)
refreshContext(context);
// 7. 执行 Runner
callRunners(context, args);
return context;
}4.2 准备环境 Environment
加载以下配置源:
| 配置源 | 优先级(高→低) |
|---|---|
| 命令行参数 | --server.port=8080 |
| 系统属性 | -Dserver.port=8080 |
| 环境变量 | SERVER_PORT=8080 |
| application.yml | 最常用 |
| application.properties | 最常用 |
4.3 创建 ApplicationContext
| Web 类型 | 创建的 Context |
|---|---|
| SERVLET | AnnotationConfigServletWebServerApplicationContext |
| REACTIVE | AnnotationConfigReactiveWebServerApplicationContext |
| NONE | AnnotationConfigApplicationContext |
4.4 准备 Context
private void prepareContext(ConfigurableApplicationContext context, ...) {
// 设置 Environment
context.setEnvironment(environment);
// 执行 ApplicationContextInitializer
applyInitializers(context);
// 注册主启动类为 BeanDefinition
load(context, sources);
}5. 阶段三:刷新容器 refresh()(核心!)
5.1 refresh() 方法概览
// AbstractApplicationContext.refresh()
public void refresh() {
// 1. 准备刷新
prepareRefresh();
// 2. 获取 BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 准备 BeanFactory
prepareBeanFactory(beanFactory);
// 4. 执行 BeanFactoryPostProcessor(解析配置类 + 自动装配)
invokeBeanFactoryPostProcessors(beanFactory);
// 5. 注册 BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 6. 初始化消息源(国际化)
initMessageSource();
// 7. 初始化事件广播器
initApplicationEventMulticaster();
// 8. 模板方法:子类扩展(创建 Web 服务器)
onRefresh();
// 9. 注册监听器
registerListeners();
// 10. 实例化所有非懒加载的单例 Bean
finishBeanFactoryInitialization(beanFactory);
// 11. 完成刷新(启动 Web 服务器 + 发布事件)
finishRefresh();
}5.2 核心步骤详解
5.2.1 invokeBeanFactoryPostProcessors()
作用:解析配置类 + 自动装配 + 注册 BeanDefinition
执行 ConfigurationClassPostProcessor
↓
┌─────────────────────────────────────────────────────────────────┐
│ 1. 解析 @ComponentScan → 扫描用户组件 │
│ 2. 解析 @Configuration → 注册配置类 │
│ 3. 解析 @Bean → 注册 Bean 方法 │
│ 4. 解析 @Import → 处理导入 │
│ └── AutoConfigurationImportSelector(延迟) │
│ 5. 自动装配 → @Conditional 过滤 → 注册 │
└─────────────────────────────────────────────────────────────────┘
↓
所有 BeanDefinition 注册完成5.2.2 onRefresh()
作用:Web 应用中创建内嵌服务器
// ServletWebServerApplicationContext.onRefresh()
protected void onRefresh() {
createWebServer(); // 创建 Tomcat/Jetty/Undertow
}5.2.3 finishBeanFactoryInitialization()
作用:实例化所有非懒加载的单例 Bean
遍历所有 BeanDefinition
↓
┌─────────────────────────────────────────────────────────────────┐
│ 对于每个非懒加载的单例 Bean: │
│ 1. 实例化(调用构造器) │
│ 2. 属性填充(@Autowired 注入) │
│ 3. 初始化(@PostConstruct、afterPropertiesSet) │
│ 4. 放入一级缓存 │
└─────────────────────────────────────────────────────────────────┘
↓
循环依赖解决:三级缓存机制5.2.4 finishRefresh()
作用:启动 Web 服务器 + 发布事件
protected void finishRefresh() {
// 启动内嵌 Web 服务器
startWebServer();
// 发布 ContextRefreshedEvent
publishEvent(new ContextRefreshedEvent(this));
}6. 阶段四:启动完成
6.1 执行 Runner
private void callRunners(ApplicationContext context, ApplicationArguments args) {
// 获取所有 Runner
List<Object> runners = new ArrayList<>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
// 按 @Order 排序后执行
for (Object runner : runners) {
if (runner instanceof ApplicationRunner) {
((ApplicationRunner) runner).run(args);
} else {
((CommandLineRunner) runner).run(args.getSourceArgs());
}
}
}6.2 两种 Runner
| Runner 类型 | 参数类型 | 使用场景 |
|---|---|---|
| ApplicationRunner | ApplicationArguments | 需要解析参数 |
| CommandLineRunner | String[] | 简单场景 |
6.3 示例
@Component
@Order(1)
public class MyRunner implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("应用启动完成,执行初始化任务...");
}
}7. 启动事件流
┌────────────────────────────────────────────────────────────────┐
│ ApplicationStartingEvent 应用开始启动 │
└────────────────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────────────────┐
│ ApplicationEnvironmentPreparedEvent 环境准备完成 │
└────────────────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────────────────┐
│ ApplicationContextInitializedEvent Context 初始化完成 │
└────────────────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────────────────┐
│ ApplicationPreparedEvent Context 准备完成 │
└────────────────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────────────────┐
│ ContextRefreshedEvent Context 刷新完成 │
└────────────────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────────────────┐
│ ApplicationStartedEvent 应用启动完成 │
└────────────────────────────────────────────────────────────────┘
↓
┌────────────────────────────────────────────────────────────────┐
│ ApplicationReadyEvent 应用就绪(可接收请求) │
└────────────────────────────────────────────────────────────────┘8. 核心数据结构存放位置
ApplicationContext
│
└── DefaultListableBeanFactory
│
├── beanDefinitionMap ← 所有 BeanDefinition
├── beanDefinitionNames ← Bean 名称列表
│
└── 继承自 DefaultSingletonBeanRegistry
├── singletonObjects ← 一级缓存
├── earlySingletonObjects ← 二级缓存
└── singletonFactories ← 三级缓存9. 面试精简版
9.1 一句话描述
创建 SpringApplication → 准备环境 → 创建 Context → refresh()(解析配置 + 自动装配 + 实例化 Bean)→ 启动 Web 服务器 → 执行 Runner
9.2 refresh() 核心步骤
| 步骤 | 方法 | 作用 |
|---|---|---|
| 1 | invokeBeanFactoryPostProcessors | 解析配置 + 自动装配 |
| 2 | registerBeanPostProcessors | 注册 BPP(AOP) |
| 3 | onRefresh | 创建 Web 服务器 |
| 4 | finishBeanFactoryInitialization | 实例化所有单例 Bean |
| 5 | finishRefresh | 启动 Web 服务器 |
9.3 高频问题
| 问题 | 答案 |
|---|---|
| 启动入口 | SpringApplication.run() |
| 配置类解析在哪 | invokeBeanFactoryPostProcessors |
| Bean 实例化在哪 | finishBeanFactoryInitialization |
| Web 服务器启动在哪 | onRefresh + finishRefresh |
| Runner 执行时机 | refresh() 完成后 |
10. 关键细节补充
10.1 为什么用户配置优先
┌─────────────────────────────────────────────────────────────────┐
│ invokeBeanFactoryPostProcessors() 执行顺序 │
│ │
│ 1. @ComponentScan 扫描用户组件 → 用户 BeanDefinition 先注册 │
│ 2. 用户 @Configuration + @Bean 解析 │
│ 3. 用户 @Import(普通 ImportSelector)处理 │
│ 4. DeferredImportSelector 处理(自动装配延迟到这里) │
│ └── @ConditionalOnMissingBean 检查时用户的已存在 │
└─────────────────────────────────────────────────────────────────┘10.2 Bean 创建的完整生命周期
finishBeanFactoryInitialization()
↓
getBean(beanName) → doGetBean() → createBean()
↓
┌─────────────────────────────────────────────────────────────────┐
│ 1. createBeanInstance() │
│ - 调用构造器实例化 │
│ - 此时属性都是 null │
│ - 放入三级缓存(ObjectFactory) │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 2. populateBean() │
│ - 属性填充 │
│ - 处理 @Autowired/@Resource/@Value │
│ - 可能触发其他 Bean 的创建(循环依赖在这里处理) │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 3. initializeBean() │
│ - invokeAwareMethods() │
│ - BPP.postProcessBeforeInitialization(@PostConstruct) │
│ - invokeInitMethods(afterPropertiesSet + init-method) │
│ - BPP.postProcessAfterInitialization(AOP 代理) │
└─────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 4. 放入一级缓存,从二三级缓存移除 │
└─────────────────────────────────────────────────────────────────┘10.3 启动过程中的三个关键 Map
| Map | 存放位置 | 内容 |
|---|---|---|
| beanDefinitionMap | DefaultListableBeanFactory | Bean 的设计图纸 |
| singletonObjects | DefaultSingletonBeanRegistry | 完整的单例 Bean |
| 三级缓存 | DefaultSingletonBeanRegistry | 解决循环依赖 |
10.4 核心本质
Spring Boot 启动的本质就是:
扫描 → 判断 → 注册 → 创建
- 扫描:找出所有可能需要的 Bean(@Component、@Bean、自动配置类)
- 判断:@Conditional 条件过滤(需不需要这个 Bean)
- 注册:生成 BeanDefinition(设计图纸)
- 创建:反射实例化 + 依赖注入 + 初始化
11. 个人理解
Spring Boot 的启动流程可以概括为"四阶段、两核心"的架构模式。
四阶段:
- 准备阶段:构建 SpringApplication 对象,通过 SPI 机制加载初始化器和监听器
- 创建容器阶段:根据 Web 类型创建对应的 ApplicationContext,加载配置文件到 Environment
- 刷新容器阶段:这是整个启动的核心,执行 refresh() 方法完成所有 Bean 的解析和创建
- 启动完成阶段:执行 Runner,发布就绪事件
两核心:
invokeBeanFactoryPostProcessors:负责「收集图纸」
- 解析 @Configuration、@ComponentScan、@Import
- 执行自动装配(DeferredImportSelector 延迟执行)
- @Conditional 条件过滤
- 最终所有 BeanDefinition 注册到 beanDefinitionMap
finishBeanFactoryInitialization:负责「按图施工」
- 遍历所有非懒加载的单例 BeanDefinition
- 按依赖关系创建 Bean(实例化 → 属性填充 → 初始化)
- 三级缓存解决循环依赖
- BeanPostProcessor 完成 AOP 代理
设计哲学:
- 约定大于配置:自动装配减少手动配置
- 用户优先:DeferredImportSelector + @ConditionalOnMissingBean 确保用户配置覆盖默认配置
- 扩展性强:通过 BeanFactoryPostProcessor、BeanPostProcessor、ApplicationListener 等扩展点,允许在各个阶段介入
整个启动流程就像是一条流水线:先准备好「设计图纸」(BeanDefinition),再按图纸「批量生产」(实例化 Bean),最后「启动服务」(Web 服务器 + Runner)。
