目录
正在加载目录…
专栏文章
专栏文章
SpringBoot 系列
1. Spring Boot 启动:从 main 到容器刷新 2. Spring Boot 日志:配置加载与 Logback 集成 3. Spring Boot 自动装配:条件注解、SPI 与 Starter

Spring Boot 启动:从 main 到容器刷新

发布于 2026-05-26 09:43 · 最后编辑于 2026-07-31 15:53 · 字数 6,033 👁 140 次阅读

基于 SpringBoot 2.4.4 源码 + 真实运行日志验证。整体分 5 个阶段:构造 → 启动准备 → 准备 ApplicationContext → 刷新 → 启动完成。每阶段标注扩展点(🔌)和日志验证(✅)。

缩写速查:../00 Spring 术语与缩写速查 · 相关笔记:../01 Spring-Framework/01 Spring 容器启动流程源码分析 · ../01 Spring-Framework/02 Spring 三级缓存与循环依赖

目录

章节说明
流程总览5 阶段结构图
阶段一:构造 SpringApplicationWebType 推断、三大组件加载
阶段二:run() 启动准备事件、Environment、配置文件加载
阶段三:准备 ApplicationContext创建上下文、BeanDefinition 加载
阶段四:刷新 ApplicationContextSpring IOC 核心、Tomcat 启动
阶段五:启动完成Runner 回调、就绪事件
扩展点汇总所有扩展点一览(含典型实现类)
BeanFactory 创建时机与 BeanDefinition 两步加载BeanFactory 何时创建、种子 BD 如何被展开

流程总览

../../../assets/01 SpringBoot 启动流程源码分析/file 20260605123838167

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,不存在 DispatcherServletREACTIVE
类路径存在 Servlet + ConfigurableWebApplicationContextSERVLET
其他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 个监听器:

监听器监听事件功能
ClearCachesApplicationListenerContextRefreshedEvent清空反射缓存、ClassLoader 缓存
ParentContextCloserApplicationListenerParentContextAvailableEvent父上下文关闭时联动关闭子上下文
FileEncodingApplicationListenerEnvironmentPreparedEvent校验 file.encoding 一致性
AnsiOutputApplicationListenerEnvironmentPreparedEvent设置 ANSI 输出
DelegatingApplicationListenerEnvironmentPreparedEvent读取 context.listener.classes 加载自定义监听器
LoggingApplicationListenerStarting/Prepared/Closed/Failed联动 LoggingSystem 生命周期
EnvironmentPostProcessorApplicationListenerEnvironmentPreparedEvent触发配置文件加载(入口)
LiquibaseServiceLocatorApplicationListenerApplicationStartingEventLiquibase 初始化

阶段二: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 默认属性源(✅ 日志验证):

属性源内容
systemPropertiesJVM 系统属性
systemEnvironmentOS 环境变量
servletContextInitParamsServletContext 初始化参数 ✅
servletConfigInitParamsServletConfig 初始化参数 ✅
configurationPropertiesSpring 配置属性绑定 ✅

配置文件扫描位置(优先级从高到低,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 解析 @ConfigurationOnClassCondition 批量判断 AutoConfiguration ✅
registerBeanPostProcessors() 🔌注册 AOP / 事务 BeanPostProcessor
finishBeanFactoryInitialization()实例化所有非懒加载 Bean,执行 @Autowired / @PostConstruct
onRefresh()启动内嵌 Tomcat/Netty ✅,注册 Servlet/Filter
publishEvent(ContextRefreshedEvent)触发 ClearCachesApplicationListener 清空缓存

关键顺序:Tomcat 在 onRefresh() 启动,晚于 Bean 实例化(④),保证所有 Bean 就绪后才开放端口。✅ 日志验证:Root WebApplicationContext: initialization completedTomcat 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
        // 典型用途:数据预热、缓存初始化、健康检查
    }
}

扩展点汇总

扩展点注册方式触发时机典型实现类典型用途
BootstrapRegistryInitializerspring.factoriescreateBootstrapContext()自定义实现refresh 前注册早期共享实例(如远程配置中心连接)
ApplicationListenerspring.factories / context.listener.classes各生命周期事件LoggingApplicationListener<br/>EnvironmentPostProcessorApplicationListener<br/>ClearCachesApplicationListener监听启动/停止事件
ApplicationContextInitializerspring.factories / context.initializer.classesrefresh 前ConfigurationWarningsApplicationContextInitializer<br/>ServerPortInfoApplicationContextInitializer<br/>ContextIdApplicationContextInitializer注册 PropertySource、激活 Profile
EnvironmentPostProcessorspring.factoriesEnvironmentPreparedEventConfigDataEnvironmentPostProcessor(加载 application.yaml)<br/>RandomValuePropertySourceEnvironmentPostProcessor加密配置解密、外部配置中心
BeanDefinitionRegistryPostProcessor@Component / @Bean / spring.factoriesinvokeBeanFactoryPostProcessors 最先执行ConfigurationClassPostProcessor(解析 @Configuration / @ComponentScan / @Import)注册额外 BeanDefinition
BeanFactoryPostProcessor@Component / @BeaninvokeBeanFactoryPostProcessorsPropertySourcesPlaceholderConfigurer(解析 ${...})<br/>EventListenerMethodProcessor修改已有 BeanDefinition
BeanPostProcessor@Component / @BeanBean 实例化前后AutowiredAnnotationBeanPostProcessor(@Autowired)<br/>CommonAnnotationBeanPostProcessor(@Resource/@PostConstruct)<br/>AbstractAutoProxyCreator(AOP 代理)AOP 代理、属性注入
ApplicationRunner@Component所有 Bean 就绪后自定义实现数据预热、缓存初始化
CommandLineRunner@Component所有 Bean 就绪后自定义实现同上,args 格式不同
afterRefresh 覆写继承 SpringApplicationrefresh 完成后自定义实现极少用,Runner 优先
AutoConfigurationspring.factoriesinvokeBeanFactoryPostProcessors 中展开DataSourceAutoConfiguration<br/>WebMvcAutoConfiguration<br/>JacksonAutoConfiguration框架自动装配

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 全部由 ConfigurationClassPostProcessorrefresh() 内完成注册。这就是 Spring Boot 自动装配与 Spring 容器 refresh 流程的衔接点。

参考资料

← 返回列表

评论 (0)

暂无评论,来留下第一条吧。
登录注册 后才能发表评论