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

【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.dtcms.com/a/322992.html

相关文章:

  • kubectl get node k8s-node01 -o yaml | grep taint -B 5 -A 5
  • 如何理解SA_RESTART”被信号中断的系统调用自动重启“?
  • 腾讯COS云存储入门
  • 笔试——Day33
  • 基于遗传优化的稀疏线阵最优排布算法matlab仿真
  • Java面向对象编程(OOP)全面解析:从基础到实践
  • 关于城市农村创业的一点构想
  • 自动生成视频的AI大模型高效创作指南
  • mac安装node.js
  • 【GPT入门】第41课 Model Scope在线平台部署Llama3
  • Serper注册无反应
  • Numpy基础(通用函数)
  • 游游的数组染色
  • 洛谷 滑动窗口 /【模板】单调队列
  • 揭秘MyBatis核心类MappedStatement
  • Java异常:认识异常、异常的作用、自定义异常
  • ChatGPT 5的编程能力宣传言过其实
  • 97-基于Python的大众点评数据分析预测系统
  • 七、《Serverless架构:按毫秒计费的成本革命》--从新浪AI推理平台50%效能提升看无服务器本质
  • 数据结构——优先级队列(PriorityQueue):一文解决 Top K 问题!
  • 可视化大屏 SDK 数据结构设计:从拖拽组件到最终渲染的全链路
  • 2025-08-09 李沐深度学习13——经典卷积神经网络 (1)
  • 嵌入式知识日常问题记录及用法总结(一)
  • C++2024 年一级
  • Vue3 学习教程,从入门到精通,Vue 3 + Tailwind CSS 全面知识点与案例详解(31)
  • buuctf:inndy_echo、actf_2019_babystack
  • 花生4CL基因家族鉴定及对干旱与盐胁迫响应分析--文献精读157
  • 【AI论文】种子扩散模型:一种具备高速推理能力的大规模扩散语言模型
  • 智慧农业-无人机视角庄稼倒伏农作物倒伏识别分割数据集labelme格式541张1类别
  • C语言指针完全指南:从入门到精通