当前位置: 首页 > ds >正文

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

文章目录

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

Spring Boot启动流程详解

整体流程如下:

1、静态方法run()调用
在这里插入图片描述
2、继续调用静态方法run()
在这里插入图片描述
3、new SpringApplication()对象
在这里插入图片描述
4、构造函数初始化
在这里插入图片描述
5、SpringApplicationshi实例run()调用
在这里插入图片描述

1. @SpringBootApplication注解作用

1.1 注解组合

@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 构造器调用链

// 1. 静态方法调用
SpringApplication.run(Application.class, args);// 2. 内部创建SpringApplication实例
new SpringApplication(primarySources).run(args);// 3. 执行构造器
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources)

2.2 构造器详细执行步骤

步骤1: 初始化基本属性

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: 设置资源加载器和主要源

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

步骤3: 推断Web应用类型

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。
this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class)
);

步骤5: 加载应用上下文初始化器
从 META-INF/spring.factories 或新版的 META-INF/spring/… 配置中找到实现了 ApplicationContextInitializer 接口的类名。
通过反射实例化它们,返回一个 List<ApplicationContextInitializer<?>>。

this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)
);

步骤6: 加载应用监听器

this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)
);

步骤7: 推断主应用类

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: 创建启动计时器

Startup startup = SpringApplication.Startup.create();

步骤2: 配置关闭钩子

if (this.registerShutdownHook) {shutdownHook.enableShutdownHookAddition();
}

步骤3: 创建Bootstrap上下文

DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();

步骤4: 配置无头属性

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

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

SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);

3.2 环境准备阶段

步骤6: 准备应用参数

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

步骤7: 准备环境

ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments
);

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

步骤8: 打印Banner

Banner printedBanner = this.printBanner(environment);

3.3 上下文创建和准备阶段

步骤9: 创建应用上下文

context = this.createApplicationContext();

根据webApplicationType创建相应的ApplicationContext:

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

步骤10: 设置应用启动器

context.setApplicationStartup(this.applicationStartup);

步骤11: 准备上下文

this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

prepareContext详细过程:

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

3.4 上下文刷新阶段

步骤12: 刷新上下文

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: 刷新后处理

this.afterRefresh(context, applicationArguments);

3.5 启动完成阶段

步骤14: 标记启动完成

startup.started();
if (this.logStartupInfo) {(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), startup);
}

步骤15: 触发started事件

listeners.started(context, startup.timeTakenToStarted());

步骤16: 调用Runner

this.callRunners(context, applicationArguments);

执行所有的ApplicationRunner和CommandLineRunner

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

if (context.isRunning()) {listeners.ready(context, startup.ready());
}
return context;

4. 与@SpringBootApplication的关联

4.1 主配置类的作用

@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创建再到应用就绪,每个步骤都有明确的职责和执行时机。

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

什么是精神内耗?
简单地说,就是心理戏太多,自己消耗自己。
所谓:
言未出,结局已演千百遍;
身未动,心中已过万重山;
行未果,假想灾难愁不展;
事已闭,过往仍在脑中演。

http://www.xdnf.cn/news/17503.html

相关文章:

  • 【从汇编语言到C语言编辑器入门笔记7】 - C语言编译器执行过程
  • Web3: 用ERC-1400革新公司股权激励
  • 【LeetCode 热题 100】(六)矩阵
  • 扩散LLM推理新范式:打破生成长度限制,实现动态自适应调节
  • 组合期权:垂直价差
  • 【股票数据API接口17】如何获取强势股池数据之Python、Java等多种主流语言实例代码演示通过股票数据接口获取数据
  • 【线性代数】线性方程组与矩阵——行列式
  • Red Hat Enterprise Linux 7.9安装Oracle 11.2.0.4单实例数据库-图文详解
  • Docker部署whisper转写模型
  • VS Git巨坑合并分支失败导致多项无关改变
  • urmom damn the jvm
  • SqlSugar vs EF Core 对比 2025年 .NET ORM
  • GPT-5深度解析:革命性AI模型的全面报告与实战指南
  • 零基础小白如何使用QGIS制作研究区地形区位图教程
  • 浅试A2A
  • 宁商平台税务升级之路:合规为纲,服务为本
  • SVM算法实战应用
  • ESP32-menuconfig(2) -- Application manager
  • 线程死锁相关知识点
  • 如何在 Ubuntu 24.04 LTS 或 22.04/20.04 上安装 Apache Maven
  • 特征值和特征向量的直觉
  • DeepSeek辅助编写的带缓存检查的数据库查询缓存系统
  • Omron(欧姆龙)SysmacStudio软件下载,定期更新(最新更新到1.63升级包)
  • 软件销售跟进思路
  • 网络基础——网络层级
  • HTML应用指南:利用GET请求获取全国Apple Store 零售店位置信息
  • 内网穿透原理与部署实战指南:从理论到企业级应用
  • pycharm常见环境配置和快捷键
  • 五、SpringBoot工程打包与运行
  • 登录注册前端详细实现 (Angular 15+)