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

Spring Boot 启动流程是怎么样的

引言

SpringBoot是一个广泛使用的Java框架,旨在简化基于Spring框架的应用程序的开发过程。在这篇文章中,我们将深入探讨SpringBoot应用程序的启动流程,了解其背后的机制。

Spring Boot 启动概览

SpringBoot应用程序的启动通常从一个包含 main 方法的类开始,例如:


@SpringBootApplication
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}

这里的SpringApplication.run是启动SpringBoot应用程序的入口。接下来,我们将深入分析这个方法及其调用的各个阶段。

 SpringApplication 类详解

SpringApplication类是SpringBoot应用程序启动过程的核心类。它负责初始化应用程序的上下文,加载配置,启动嵌入式服务器等。

SpringApplication构造函数

SpringApplication类有多个构造函数,常用的是接收一个或多个Class<?> 参数的构造函数:


public SpringApplication(Class<?>... primarySources) {this.setInitializers((Collection) this.getSpringFactoriesInstances(ApplicationContextInitializer.class));this.setListeners((Collection) this.getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass = this.deduceMainApplicationClass();
}

这里设置了初始化器和监听器,并推断出主应用程序类。

run 方法

SpringApplication.run方法是启动SpringBoot应用程序的入口:


public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {return (new SpringApplication(primarySources)).run(args);
}

这个方法内部调用了SpringApplication实例的run方法:


public ConfigurableApplicationContext run(String... args) {// 初始化阶段this.configureHeadlessProperty();SpringApplicationRunListeners listeners = this.getRunListeners(args);listeners.starting();// 环境准备阶段ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);this.configureIgnoreBeanInfo(environment);// 上下文创建阶段Banner printedBanner = this.printBanner(environment);ConfigurableApplicationContext context = this.createApplicationContext();this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);// 上下文刷新阶段this.refreshContext(context);this.afterRefresh(context, applicationArguments);listeners.finished(context, null);// 应用程序运行阶段this.callRunners(context, applicationArguments);return context;
}

源码解析

准备阶段

在准备阶段中,Spring Boot 会加载应用程序的初始设置,并创建 Spring Boot 上下文。这个阶段的核心源码是 SpringApplication 类的 run() 方法,它会调用 Spring Boot 的各个初始化器进行初始化和准备工作。

public ConfigurableApplicationContext run(String... args) {// 启动计时器StopWatch stopWatch = new StopWatch();stopWatch.start();// 定义应用程序上下文和异常报告器列表ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();// 配置 Headless 属性configureHeadlessProperty();// 获取 Spring Boot 启动监听器SpringApplicationRunListeners listeners = getRunListeners(args);// 执行启动监听器的 starting 方法listeners.starting();try {// 解析命令行参数ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 准备应用程序环境ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);// 配置忽略 BeanInfoconfigureIgnoreBeanInfo(environment);// 打印 BannerBanner printedBanner = printBanner(environment);// 创建应用程序上下文context = createApplicationContext();// 获取异常报告器,关于异常报告,我下次专门讲一下SpringBoot 的异常收集器。exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);// 准备应用程序上下文prepareContext(context, environment, listeners, applicationArguments, printedBanner);// 刷新应用程序上下文refreshContext(context);// 刷新后操作afterRefresh(context, applicationArguments);// 停止计时器stopWatch.stop();// 记录启动日志if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}// 执行启动监听器的 started 方法listeners.started(context);// 执行 RunnercallRunners(context, applicationArguments);} catch (Throwable ex) {// 处理启动失败handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {// 执行启动监听器的 running 方法listeners.running(context);} catch (Throwable ex) {// 处理启动失败handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}// 返回应用程序上下文return context;}

在 run() 方法中,Spring Boot 首先会创建一个 StopWatch 对象,用于记录整个启动过程的耗时。然后,Spring Boot 会调用 getRunListeners(args) 方法获取 Spring Boot 的各个启动监听器,并调用starting() 方法通知这些监听器启动过程已经开始。接着调用 prepareEnvironment(listeners, applicationArguments) 方法创建应用程序的环境变量。

这个方法会根据用户的配置和默认设置创建一个 ConfigurableEnvironment对象,并将其传给后面的 createApplicationContext() 方法。printBanner(environment) 方法打印启动界面的 Banner,调用 refreshContext(context)方法刷新上下文。这个方法会启动上下文,执行各种启动任务,包括创建 Web 服务器、加载应用程序的配置、初始化各种组件等。具体的启动任务会在刷新上下文阶段中进行。

应用上下文创建阶段

在应用上下文创建阶段中,Spring Boot 会创建应用程序的上下文,包括各种配置信息、Bean 的加载和初始化等。这个阶段的核心源码是 Spring Boot 自动配置机制,通过扫描 classpath 中的配置文件,自动加载和配置各种组件和 Bean。

protected ConfigurableApplicationContext createApplicationContext() {Class<?> contextClass = this.applicationContextClass;if (contextClass == null) {try {switch (this.webApplicationType) {case SERVLET:contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);break;case REACTIVE:contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);break;default:contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);}}catch (ClassNotFoundException ex) {throw new IllegalStateException("Unable to create a default ApplicationContext, " +"please specify an ApplicationContextClass", ex);}}return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}

在 createApplicationContext() 方法中,Spring Boot 首先会判断应用程序的类型,如果是 Web 应用程序,则会创建一个 WebApplicationContext;否则,会创建一个普通的 ApplicationContext。调用 BeanUtils.instantiateClass(contextClass) 方法创建应用程序的上下文。这个方法会根据上面的逻辑创建一个相应的 ApplicationContext。调用 load() 方法加载应用程序的配置。

这个方法会扫描 classpath 中的各种配置文件,例如 application.propertiesapplication.ymlMETA-INF/spring.factories 等,自动配置各种组件和 Bean。调用 postProcessApplicationContext() 方法对应用程序的上下文进行后处理。这个方法会调用各种初始化器和监听器,执行各种初始化任务。

刷新上下文阶段

在刷新上下文阶段中,Spring Boot 会执行各种启动任务,包括创建 Web 服务器(刚才我们跟源码的时候也看到了,如上我的截图)、加载应用程序的配置、初始化各种组件等。这个阶段的核心源码是 Spring Boot 的刷新机制,它会调用各种初始化器和监听器,执行各种启动任务。


protected void refreshContext(ConfigurableApplicationContext applicationContext) {refresh(applicationContext);if (this.registerShutdownHook) {try {applicationContext.registerShutdownHook();}catch (AccessControlException ex) {// Not allowed in some environments.}}
}

在 refreshContext() 方法中调用 refresh(applicationContext) 方法刷新上下文。这个方法是 ApplicationContext 接口的核心方法,会启动上下文,执行各种启动任务。调用 registerShutdownHook() 方法注册应用程序的关闭钩子。这个方法会在应用程序关闭时自动执行,清理资源、关闭线程等,所以我们利用此特性在服务关闭的时候清理一些资源。并向外部发送告警通知。

在 refresh(applicationContext) 方法中,Spring Boot 会执行上下文的各种启动任务,包括创建 Web 服务器、加载应用程序的配置、初始化各种组件等。具体的启动任务会调用各种初始化器和监听器,例如:

for (ApplicationContextInitializer<?> initializer : getInitializers()) {initializer.initialize(applicationContext);
}

另外,Spring Boot 还会调用各种监听器,我们不做赘述,例如:

for (ApplicationListener<?> listener : getApplicationListeners()) {if (listener instanceof SmartApplicationListener) {SmartApplicationListener smartListener = (SmartApplicationListener) listener;if (smartListener.supportsEventType(eventType)&& smartListener.supportsSourceType(sourceType)) {invokeListener(smartListener, event);}}else if (supportsEvent(listener, eventType)) {invokeListener(listener, event);}
}

相关文章:

Spring Boot 启动流程是怎么样的

引言 SpringBoot是一个广泛使用的Java框架&#xff0c;旨在简化基于Spring框架的应用程序的开发过程。在这篇文章中&#xff0c;我们将深入探讨SpringBoot应用程序的启动流程&#xff0c;了解其背后的机制。 Spring Boot 启动概览 SpringBoot应用程序的启动通常从一个包含 m…...

【学习笔记】数据结构(三)

栈和队列 文章目录 栈和队列3.1 栈 - Stack3.1.1 抽象数据类型栈的定义3.1.2 栈的表示和实现 3.2 栈的应用举例3.2.1 数制转换3.2.2 括号匹配的检验3.2.3 迷宫求解3.2.4 表达式求值 - 波兰、逆波兰3.2.5 反转一个字符串或者反转一个链表 3.3 栈与递归的实现3.4 队列 - Queue3.4…...

学习python笔记:10,requests,enumerate,numpy.array

requests库&#xff0c;用于发送 HTTP 请求的 Python 库。 requests 是一个用于发送 HTTP 请求的 Python 库。它使得发送 HTTP 请求变得简单且人性化。以下是一些基本的 requests 函数及其用途&#xff1a; requests.get(url, **kwargs) 发送一个 GET 请求到指定的 URL。 i…...

经典神经网络(13)GPT-1、GPT-2原理及nanoGPT源码分析(GPT-2)

经典神经网络(13)GPT-1、GPT-2原理及nanoGPT源码分析(GPT-2) 2022 年 11 月&#xff0c;ChatGPT 成功面世&#xff0c;成为历史上用户增长最快的消费者应用。与 Google、FaceBook等公司不同&#xff0c;OpenAI 从初代模型 GPT-1 开始&#xff0c;始终贯彻只有解码器&#xff0…...

MySQL库与表的操作

目录 一、登录并进入数据库 1、登录 2、USE 命令 检查当前数据库 二、库的操作 1、创建数据库语法 2、举例演示 3、退出 三、字符集和校对规则 1、字符集&#xff08;Character Set&#xff09; 2、校对集&#xff08;Collation&#xff09; 总结 3、操作命令 …...

TTS 语音合成技术学习

TTS 语音合成技术 TTS&#xff08;Text-to-Speech&#xff0c;文字转语音&#xff09;技术是一种能够将文字内容转换为自然语音的技术。通过 TTS&#xff0c;机器可以“说话”&#xff0c;这大大增强了人与机器之间的互动能力。无论是在语音助手、导航系统还是电子书朗读器中&…...

小公司做自动化的困境

1. 人员数量不够 非常常见的场景, 开发没几个, 凭什么测试要那么多, 假设这里面有3个测试, 是不是得有1个人会搞框架? 是不是得有2人搞功能测试, 一个人又搞框架, 有些脚本, 真来得及吗? 2. 人员基础不够 现在有的大公司, 是这样子协作的, 也就是某模块需求谁谁测试的, 那么…...

基于pytorch框架的手写数字识别(保姆级教学)

1、前言 本文基于PyTorch框架,采用CNN卷积神经网络实现MNIST手写数字识别,不仅可以在GPU上,同时也可以在CPU上运行。方便即使只有CPU的小伙伴也可以运行该模型。本博客手把手教学,如何手写网络层(3层),以及模型训练,详细介绍各参数含义与用途。 2、模型源码解读 该模型…...

注意力机制在大语言模型中的应用

在大语言模型中&#xff0c;注意力机制&#xff08;Attention Mechanism&#xff09;用于捕获输入序列中不同标记&#xff08;token&#xff09;之间的关系和依赖性。这种机制可以动态地调整每个标记对当前处理任务的重要性&#xff0c;从而提高模型的性能。具体来说&#xff0…...

qt 实现对字体高亮处理原理

在Qt中实现对文本的字体高亮处理&#xff0c;通常涉及到使用QTextDocument、QTextCharFormat和QSyntaxHighlighter。下面是一个简单的例子&#xff0c;演示如何为一个文本编辑器&#xff08;假设是QTextEdit&#xff09;添加简单的关键词高亮功能&#xff1a; 步骤 1: 定义关键…...

SAP中通过财务科目确定分析功能来定位解决BILLING问题实例

接用户反馈&#xff0c;一笔销售订单做发货后做销售发票时&#xff0c;没有成功过账到财务&#xff0c;提示财户确定错误。 这个之前可以通过VF02中点击小绿旗来重新执行过财动作&#xff0c;看看有没有相应日志来定位问题。本次尝试用此方法&#xff0c;也没有找到相关线索。 …...

充电站,正在杀死加油站

最近&#xff0c;深圳公布了一组数据&#xff0c;深圳的超级充电站数量已超过传统加油站数量&#xff0c;充电枪数量也已超过加油枪数量。 从全国范围看&#xff0c;加油站关停的速度在加快。 充电站正在杀死加油站。 加油站&#xff0c;未来何去何从&#xff1f; 01. 减少 我…...

哪个牌子的超声波清洗机好?四样超卓超声波清洗机独具特色!

眼镜是许多人日常生活中必不可少的工具&#xff0c;然而&#xff0c;相信很多人都有过清洗眼镜的烦恼。传统的清洗眼镜的方法往往不够彻底&#xff0c;容易留下污渍或者划伤镜片。因此&#xff0c;超声波洗眼镜机成为了现代人清洗眼镜的新选择。超声波洗眼镜机通过利用超声波震…...

vue3中若v-model绑定的响应字段出现三级,该如何实现rules验证规则

比如以下内容&#xff1a; 配置的rules内容 const rulesref({title:[{required:true,message:"请输入标题",trigger:"blur"},{max:50,message:"最大不能超过256个字",trigger:"blur"}],Category:[{required:true,message:"请选择…...

Docker-Compose一键部署项目

Docker-Compose一键部署项目 目录 Docker-Compose一键部署项目介绍部署Django项目项目目录结构 docker-compose.ymlnginx的default.conf文件后端Dockerfile文件mysql.env一键部署DNS域名解析引起的跨域问题 介绍 Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的…...

【C++】相机标定源码笔记-线激光点云处理工具类

一个线激光点云处理工具类&#xff0c;它包含了一系列的方法用于处理和分析线激光扫描得到的点云数据。提供的功能包括&#xff1a; 通过文件或直接数据设置点云。计算线激光在机器人坐标系下的精度&#xff0c;输出内点的平均距离、最大距离、最小距离、总点数和内点数。提供了…...

解决Transformer根本缺陷,所有大模型都能获得巨大改进

即使最强大的 LLM 也难以通过 token 索引来关注句子等概念&#xff0c;现在有办法了。 最近两天&#xff0c;马斯克和 LeCun 的口水战妥妥成为大家的看点。这两位 AI 圈的名人你来我往&#xff0c;在推特&#xff08;现为 X&#xff09;上相互拆对方台。 LeCun 在宣传自家最新论…...

如何排查Java应用的死锁

排查Java应用中的死锁问题是一个复杂但重要的任务&#xff0c;因为死锁会导致应用程序停止响应&#xff0c;影响用户体验和系统稳定性。以下是一些方法和步骤&#xff0c;帮助你排查Java应用中的死锁。 1. 理解死锁的概念 在计算机科学中&#xff0c;死锁是指两个或多个线程相…...

JS面试题1

1. 延迟加载JS有哪些方式&#xff1f; defer: 等html全部解析完成&#xff0c;才会执行js代码&#xff0c;顺次执行js脚本 async&#xff1a;是和html解析同步的&#xff0c;不是顺次执行js脚本&#xff08;当有很多个js时&#xff09;&#xff0c;是谁先加载完谁先执行。 <…...

Linux网络 - 再谈、详谈UDP和TCP协议

文章目录 前言预备netstatpidofcat /etc/services 一、UDP协议UDP协议端格式UDP的缓冲区基于UDP的应用层协议 二、TCP协议1.TCP协议段格式确认应答(ACK)机制三次握手疑问1 最后一次客户端发给服务端的ACK请求怎么保证服务端能够收到&#xff1f; 四次挥手疑问2 为什么挥手是四次…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲

文章目录 前言第一部分&#xff1a;体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分&#xff1a;体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用

文章目录 一、背景知识&#xff1a;什么是 B-Tree 和 BTree&#xff1f; B-Tree&#xff08;平衡多路查找树&#xff09; BTree&#xff08;B-Tree 的变种&#xff09; 二、结构对比&#xff1a;一张图看懂 三、为什么 MySQL InnoDB 选择 BTree&#xff1f; 1. 范围查询更快 2…...

适应性Java用于现代 API:REST、GraphQL 和事件驱动

在快速发展的软件开发领域&#xff0c;REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名&#xff0c;不断适应这些现代范式的需求。随着不断发展的生态系统&#xff0c;Java 在现代 API 方…...

uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)

UniApp 集成腾讯云 IM 富媒体消息全攻略&#xff08;地理位置/文件&#xff09; 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型&#xff0c;核心实现方式&#xff1a; 标准消息类型&#xff1a;直接使用 SDK 内置类型&#xff08;文件、图片等&#xff09;自…...