【Spring Boot启动流程底层源码详解】

文章目录

  • [Spring Boot启动流程详解](#Spring Boot启动流程详解)
    • 整体流程如下:
    • [1. @SpringBootApplication注解作用](#1. @SpringBootApplication注解作用)
      • [1.1 注解组合](#1.1 注解组合)
      • [1.2 注解功能](#1.2 注解功能)
    • [2. SpringApplication构造器执行流程](#2. SpringApplication构造器执行流程)
      • [2.1 构造器调用链](#2.1 构造器调用链)
      • [2.2 构造器详细执行步骤](#2.2 构造器详细执行步骤)
    • [3. SpringApplication.run()方法执行流程](#3. SpringApplication.run()方法执行流程)
      • [3.1 启动准备阶段](#3.1 启动准备阶段)
      • [3.2 环境准备阶段](#3.2 环境准备阶段)
      • [3.3 上下文创建和准备阶段](#3.3 上下文创建和准备阶段)
      • [3.4 上下文刷新阶段](#3.4 上下文刷新阶段)
      • [3.5 启动完成阶段](#3.5 启动完成阶段)
    • [4. 与@SpringBootApplication的关联](#4. 与@SpringBootApplication的关联)
      • [4.1 主配置类的作用](#4.1 主配置类的作用)
      • [4.2 注解处理时机](#4.2 注解处理时机)
      • [4.3 自动配置执行流程](#4.3 自动配置执行流程)
    • [5. 完整流程图](#5. 完整流程图)
    • [6. 关键扩展点](#6. 关键扩展点)

Spring Boot启动流程详解

整体流程如下:

1、静态方法run()调用

2、继续调用静态方法run()

3、new SpringApplication()对象

4、构造函数初始化

5、SpringApplicationshi实例run()调用

1. @SpringBootApplication注解作用

1.1 注解组合

java 复制代码
@SpringBootConfiguration  // 等同于@Configuration,标识这是配置类
@EnableAutoConfiguration  // 启用自动配置机制
@ComponentScan           // 启用组件扫描
public @interface SpringBootApplication {
    // ...
}

1.2 注解功能

  • @SpringBootConfiguration: 将启动类标记为配置类,相当于Spring的@Configuration
  • @EnableAutoConfiguration: 启用Spring Boot的自动配置机制,根据classpath自动配置Bean
  • @ComponentScan: 扫描当前包及子包下的组件(@Component、@Service、@Repository等)

2. SpringApplication构造器执行流程

2.1 构造器调用链

java 复制代码
// 1. 静态方法调用
SpringApplication.run(Application.class, args);

// 2. 内部创建SpringApplication实例
new SpringApplication(primarySources).run(args);

// 3. 执行构造器
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources)

2.2 构造器详细执行步骤

步骤1: 初始化基本属性

java 复制代码
this.sources = new LinkedHashSet();                    // 存储配置源
this.bannerMode = Mode.CONSOLE;                        // Banner显示模式
this.logStartupInfo = true;                           // 是否记录启动信息
this.addCommandLineProperties = true;                 // 是否添加命令行属性
this.addConversionService = true;                     // 是否添加转换服务
this.headless = true;                                 // 无头模式
this.registerShutdownHook = true;                     // 注册关闭钩子
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;  //设置用于创建 ApplicationContext 的工厂(ApplicationContextFactory 接口
this.applicationStartup = ApplicationStartup.DEFAULT; // Instrumentation / 启动跟踪的钩子(ApplicationStartup 接口),用于收集启动事件/指标(例如用于可观察性、记录启动步骤)

步骤2: 设置资源加载器和主要源

java 复制代码
this.resourceLoader = resourceLoader;                  // 设置资源加载器
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));  // 设置主配置类

步骤3: 推断Web应用类型

java 复制代码
this.webApplicationType = WebApplicationType.deduceFromClasspath();
  • NONE: 非Web应用
  • SERVLET: 传统Servlet Web应用
  • REACTIVE: 响应式Web应用

步骤4: 加载Bootstrap初始化器

根据 spring.factories 或 META-INF/spring/org.springframework.boot.BootstrapRegistryInitializer 等配置文件,

找到所有实现了 BootstrapRegistryInitializer 接口的类。

它会:

  1. 从类路径扫描这些实现类的全限定类名
  2. 通过反射实例化它们(可能还会做一些依赖注入或排序)
  3. 返回一个 List。
java 复制代码
this.bootstrapRegistryInitializers = new ArrayList(
    this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class)
);

步骤5: 加载应用上下文初始化器

从 META-INF/spring.factories 或新版的 META-INF/spring/... 配置中找到实现了 ApplicationContextInitializer 接口的类名。

通过反射实例化它们,返回一个 List<ApplicationContextInitializer<?>>。

java 复制代码
this.setInitializers(
    this.getSpringFactoriesInstances(ApplicationContextInitializer.class)
);

步骤6: 加载应用监听器

java 复制代码
this.setListeners(
    this.getSpringFactoriesInstances(ApplicationListener.class)
);

步骤7: 推断主应用类

java 复制代码
this.mainApplicationClass = this.deduceMainApplicationClass();

总结

加载对应的监听器或者初始化器的核心方法有什么?
SpringApplication#getSpringFactoriesInstances(),然后依赖SpringFactoriesLoader.forDefaultResourceLocation().load()方法,其中SpringFactoriesLoader.forDefaultResourceLocation()创建一个 SpringFactoriesLoader 实例,里面指定了加载指定类的类加载器,默认去 META-INF/spring.factories 路径扫描配置文件。然后实例调用load去加载指定的Class对应的实现类
拓展
SpringFactoriesLoader 是什么?

  • SpringFactoriesLoader 是 Spring 提供的一个工具类(在org.springframework.core.io.support 包下)。

  • 它的核心功能:

    扫描并读取所有类路径下的 META-INF/spring.factories 配置文件,

    并根据你指定的接口或抽象类,返回对应的实现类全限定名(然后可以反射实例化)。

3. SpringApplication.run()方法执行流程

3.1 启动准备阶段

步骤1: 创建启动计时器

java 复制代码
Startup startup = SpringApplication.Startup.create();

步骤2: 配置关闭钩子

java 复制代码
if (this.registerShutdownHook) {
    shutdownHook.enableShutdownHookAddition();
}

步骤3: 创建Bootstrap上下文

java 复制代码
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();

步骤4: 配置无头属性

java 复制代码
this.configureHeadlessProperty();  // 设置java.awt.headless系统属性

步骤5: 获取运行时监听器

java 复制代码
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);

3.2 环境准备阶段

步骤6: 准备应用参数

java 复制代码
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

步骤7: 准备环境

java 复制代码
ConfigurableEnvironment environment = this.prepareEnvironment(
    listeners, bootstrapContext, applicationArguments
);

创建并加载应用运行环境(Environment),确保所有配置和 Profile 在容器刷新之前准备就绪,这时候容器就具备了某个配置文件对应的环境。

步骤8: 打印Banner

java 复制代码
Banner printedBanner = this.printBanner(environment);

3.3 上下文创建和准备阶段

步骤9: 创建应用上下文

java 复制代码
context = this.createApplicationContext();

根据webApplicationType创建相应的ApplicationContext:

  • SERVLET: AnnotationConfigServletWebServerApplicationContext
  • REACTIVE: AnnotationConfigReactiveWebServerApplicationContext
  • NONE: AnnotationConfigApplicationContext

步骤10: 设置应用启动器

java 复制代码
context.setApplicationStartup(this.applicationStartup);

步骤11: 准备上下文

java 复制代码
this.prepareContext(bootstrapContext, context, environment, 
                   listeners, applicationArguments, printedBanner);

prepareContext详细过程:

  • 设置环境
  • 执行ApplicationContextInitializer
  • 触发监听器的contextPrepared事件
  • 注册单例Bean(如applicationArguments、printedBanner)
  • 加载配置源(主配置类等)
  • 触发监听器的contextLoaded事件

3.4 上下文刷新阶段

步骤12: 刷新上下文

java 复制代码
this.refreshContext(context);

这是核心步骤,执行Spring容器的refresh()方法:

  • prepareRefresh(): 准备刷新
  • obtainFreshBeanFactory(): 获取BeanFactory
  • prepareBeanFactory(): 准备BeanFactory
  • postProcessBeanFactory(): 后处理BeanFactory
  • invokeBeanFactoryPostProcessors(): 执行BeanFactory后处理器
  • registerBeanPostProcessors(): 注册Bean后处理器
  • initMessageSource(): 初始化消息源
  • initApplicationEventMulticaster(): 初始化事件多播器
  • onRefresh(): 刷新特定上下文(如启动Web服务器)
  • registerListeners(): 注册监听器
  • finishBeanFactoryInitialization(): 完成Bean工厂初始化(实例化所有单例Bean)
  • finishRefresh(): 完成刷新

步骤13: 刷新后处理

java 复制代码
this.afterRefresh(context, applicationArguments);

3.5 启动完成阶段

步骤14: 标记启动完成

java 复制代码
startup.started();
if (this.logStartupInfo) {
    (new StartupInfoLogger(this.mainApplicationClass))
        .logStarted(this.getApplicationLog(), startup);
}

步骤15: 触发started事件

java 复制代码
listeners.started(context, startup.timeTakenToStarted());

步骤16: 调用Runner

java 复制代码
this.callRunners(context, applicationArguments);

执行所有的ApplicationRunner和CommandLineRunner

步骤17: 触发ready事件并返回

java 复制代码
if (context.isRunning()) {
    listeners.ready(context, startup.ready());
}
return context;

4. 与@SpringBootApplication的关联

4.1 主配置类的作用

java 复制代码
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);  // Application.class作为primarySources传入
    }
}

4.2 注解处理时机

  1. 构造器阶段: Application.class被设置为primarySources
  2. prepareContext阶段: 主配置类被注册到容器中
  3. refresh阶段:
    • @ComponentScan: 触发组件扫描,发现所有@Component等注解的类
    • @EnableAutoConfiguration: 触发自动配置,加载所有符合条件的自动配置类
    • @SpringBootConfiguration: 作为配置类被处理

4.3 自动配置执行流程

  1. EnableAutoConfigurationImportSelector被触发
  2. 读取META-INF/spring.factories中的自动配置类
  3. 根据条件注解(@ConditionalOnClass、@ConditionalOnMissingBean等)筛选
  4. 实例化符合条件的自动配置类
  5. 注册自动配置的Bean到容器中

5. 完整流程图

复制代码
@SpringBootApplication
       ↓
SpringApplication.run()
       ↓
1. 创建SpringApplication实例
   ├── 推断Web应用类型
   ├── 加载初始化器和监听器
   └── 推断主应用类
       ↓
2. 执行run()方法
   ├── 创建Bootstrap上下文
   ├── 准备环境(Environment)
   ├── 创建应用上下文(ApplicationContext)
   ├── 准备上下文
   ├── 刷新上下文(refresh)
   │   ├── 组件扫描(@ComponentScan)
   │   ├── 自动配置(@EnableAutoConfiguration)
   │   └── 实例化所有Bean
   ├── 调用Runner
   └── 启动完成

6. 关键扩展点

  • ApplicationContextInitializer: 在上下文refresh之前执行
  • ApplicationListener: 监听应用启动过程中的各种事件
  • BeanFactoryPostProcessor: 在Bean定义加载后、Bean实例化前执行
  • BeanPostProcessor: 在Bean实例化过程中执行
  • ApplicationRunner/CommandLineRunner: 在应用启动完成后执行

这个流程确保了Spring Boot应用的完整启动,从注解解析到Bean创建再到应用就绪,每个步骤都有明确的职责和执行时机。

本人水平有限,有错的地方还请批评指正。

什么是精神内耗?

简单地说,就是心理戏太多,自己消耗自己。

所谓:

言未出,结局已演千百遍;

身未动,心中已过万重山;

行未果,假想灾难愁不展;

事已闭,过往仍在脑中演。