Spring Boot 启动加速
一、简介
本文将带你了解如何通过调整 Spring 应用的配置、JVM 参数和使用 GraalVM 原生镜像来缩短 Spring Boot 的启动时间。
二、调整 Spring 应用
首先,创建一个 Spring Boot(2.5.4)应用,添加 Spring Web、Spring Actuator 和 Spring Security 依赖。
还要添加 spring-boot-maven-plugin 插件,并配置将应用打包到 jar 文件中:
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot.version}</version> <configuration> <finalName>springStartupApp</finalName> <mainClass>com.baeldung.springStart.SpringStartApplication</mainClass> </configuration> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions>
</plugin>
使用标准的 java -jar 命令运行 jar 文件,并查看应用的启动时间。
c.b.springStart.SpringStartApplication : Started SpringStartApplication in 3.403 seconds (JVM running for 3.961)
如上,应用启动时间约为 3.4 秒。我们把这个时间作为下文调整的参考。
1、延迟初始化
Spring 支持延迟初始化。延迟初始化意味着 Spring 不会在启动时创建所有 Bean。此外,Spring 在需要 Bean 之前不会注入任何依赖。从 Spring Boot 2.2 版开始,就可以使用 application.properties 启用延迟始化:
spring.main.lazy-initialization=true
新建一个 jar 文件并按上例配置、启动后,新的启动时间略有改善:
c.b.springStart.SpringStartApplication : Started SpringStartApplication in 2.95 seconds (JVM running for 3.497)
根据代码规模的大小,延迟初始化可以显著缩短启动时间。启动时间的减少取决于应用的依赖关系。
此外,在开发过程中使用 DevTools 热重启功能时,延迟初始化也有好处。通过延迟初始化增加重启次数,JVM 可以更好地优化代码。
不过,延迟初始化也有一些缺点。最明显的缺点是应用处理第一个请求的速度会变慢,因为 Spring 需要时间来初始化所需的 Bean。另一个缺点是可能会在启动时错过一些错误。这可能会在运行时导致 ClassNotFoundException。
2、排除不必要的自动配置
Spring Boot 的理念是约定大于配置。Spring 可能会初始化应用并不需要的 Bean。我们可以通过启动日志检查所有自动配置的 Bean。
在 application.properties 中将 org.springframework.boot.autoconfigure 的日志级别设置为 DEBUG:
logging.level.org.springframework.boot.autoconfigure=DEBUG
在日志中,可以看到专门用于自动配置的日志信息,从以下几行开始:
============================
CONDITIONS EVALUATION REPORT
============================
通过这个日志报告,可以使用 @EnableAutoConfiguration 排除应用中不会用到的自动配置:
@EnableAutoConfiguration(exclude = {JacksonAutoConfiguration.class, JvmMetricsAutoConfiguration.class, LogbackMetricsAutoConfiguration.class, MetricsAutoConfiguration.class})
如上,不使用 Jackson JSON 和一些指标配置,就可以节省一些启动时间:
c.b.springStart.SpringStartApplication : Started SpringStartApplication in 3.183 seconds (JVM running for 3.732)
3、其他小调整
Spring Boot 自带一个嵌入式 servlet 容器。默认情况下,使用的是 Tomcat。虽然 Tomcat 在大多数情况下已经足够好,但其他 servlet 容器的性能可能更高。在测试中,JBoss 的 Undertow 比 Tomcat 或 Jetty 性能更好。它需要的内存更少,平均响应时间也更长。
修改 pom.xml,切换到 Undertow:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
在 classpath 扫描方面可以有以下小改进。Spring 的 classpath 扫描速度很快。当代码库较大时,可以通过创建静态索引来缩短启动时间。
添加一个依赖 spring-context-indexer 来生成索引。Spring 不需要任何额外配置。在编译时,Spring 会在 META-INF\spring.components 中创建一个额外的文件。Spring 会在启动时自动使用该文件:
<dependency><groupId>org.springframework</groupId><artifactId>spring-context-indexer</artifactId><version>${spring.version}</version><optional>true</optional>
</dependency>
由于我们只有一个 Spring 组件,因此这一调整在测试中没有产生显著效果。
application.properties(或 .yml)配置文件有几个有效的存放位置,最常见的是在 classpath 根目录下或与 jar 文件在同一文件夹下。我们可以通过使用 spring.config.location 参数设置显式路径来避免搜索多个位置,从而节省几毫秒的搜索时间:
java -jar .\target\springStartupApp.jar --spring.config.location=classpath:/application.properties
最后,Spring Boot 提供了一些 MBean,用于通过 JMX 监控应用。完全关闭 JMX 可以避免创建这些 Bean 的成本:
spring.jmx.enabled=false
三、调整 JVM
1、Verify 参数
此参数用于设置字节码验证模式。字节码验证可确定类的格式是否正确,是否符合 JVM 规范约束。
该参数有几个选项:
-Xverify是默认值,可对所有非 “boot” 类进行验证。-Xverify:all可对所有类进行验证。这种设置会对启动性能产生很大的负面影响。-Xverify:none(或-Xnoverify)该选项可完全禁用校验器,大大缩短启动时间。
在启动 JVM 时设置此参数。
从 JDK 13 开始及其后续版本中,不建议继续使用 -Xverify:none 和-noverify 参数。
java -jar -noverify .\target\springStartupApp.jar
JVM 会警告这个选项已被弃用,此外,启动时间也会缩短:
c.b.springStart.SpringStartApplication : Started SpringStartApplication in 3.193 seconds (JVM running for 3.686)
这个选项会有一个重大的问题,可能导致应用在运行时因错误而崩溃,而这些错误本应该提前捕获到的。这也是该选项在 Java 13 中被标记为废弃的原因之一。
2、TieredCompilation 参数
Java 7 引入了分层编译。HotSpot 编译器将对代码进行不同层次的编译。
Java 代码首先被解释为字节码。然后,字节码被编译成机器码。这种编译发生在方法级别。C1 编译器会在调用一定次数后对方法进行编译。在运行更多次后,C2 编译器会对其进行编译,从而进一步提高性能。
使用 -XX:-TieredCompilation 参数,可以禁用中间编译层。这意味着我们的方法将使用 C2 编译器进行解释或编译,以实现最大优化。这不会降低启动速度。
要禁用 C2 编译。可以使用 -XX:TieredStopAtLevel=1 选项。结合 -noverify 参数,可以缩短启动时间。遗憾的是,这会降低 JIT 编译器后期的运行速度。
使用 -XX:TieredStopAtLevel=1 选项就带来了显著的改进:
c.b.springStart.SpringStartApplication : Started SpringStartApplication in 2.754 seconds (JVM running for 3.172)
如果同时使用本节中的 2 个参数,还能进一步缩短启动时间:
java -jar -XX:TieredStopAtLevel=1 -noverify .\target\springStartupApp.jar
c.b.springStart.SpringStartApplication : Started SpringStartApplication in 2.537 seconds (JVM running for 2.912)
四、Spring Native
原生镜像(Native image)是使用 AOT(Ahead-Of-Time)编译器编译的 Java 代码,并打包成可执行文件。它不需要 Java 就能运行。由于没有 JVM 的开销,因此程序运行速度更快,对内存的依赖性也更小。GraalVM 项目引入了原生镜像和所需的构建工具。
Spring Native是一个实验性模块,它支持使用 GraalVM 原生镜像编译器对 Spring 应用程序进行原生编译。AOT 编译器会在构建过程中执行多项任务,从而缩短启动时间(静态分析、删除未使用的代码、创建固定的类路径等)。
原生镜像仍有一些限制:
- 它不支持所有 Java 功能
- 反射功能需要特殊配置
- 延迟类加载不能使用
- Windows 兼容性问题
要将应用编译为原生镜像,需要在 pom.xml 中添加 spring-aot 和 spring-aot-maven-plugin 依赖。Maven 将在 target 文件夹中,通过 package 命令创建原生镜像。
相关文章:
Spring Boot 启动加速
一、简介 本文将带你了解如何通过调整 Spring 应用的配置、JVM 参数和使用 GraalVM 原生镜像来缩短 Spring Boot 的启动时间。 二、调整 Spring 应用 首先,创建一个 Spring Boot(2.5.4)应用,添加 Spring Web、Spring Actuator …...
UDP数据报文格式
...
软考-系统架构-2023-反思
2023年11月4日,参加了软考的高级架构设计考试。针对于这次考试做一些总结和反思。 我的考试准备周期非常长,但是实际的时间非常少。差不多一年前我就开始有这个计划和想法准备考试了,但是前期基本上就是翻翻书,跟没有开始区别并不…...
day52
今日内容概要 web应用程序 手写web框架(帮助我们理解别人写好的成熟框架、重点在于思路的理解、代码无需掌握) Django框架的学习 Python中得主流框架 框架的下载、安装、版本、怎么启动、怎么使用等 三板斧问题 web应用程序 Django框架是一款专门用来开发web应用的框架 …...
Mysql关联查询
Mysql关联查询 1、数据准备 # 班级表 create table class(id int primary key auto_increment,name varchar(20),description varchar(100) );# 学生表 create table student(id int primary key auto_increment,sn varchar(20),name varchar(20),email varchar(20),class_id…...
MOSFET和IGBT栅极驱动器TLP250H(D4-TP1,F)电路的基本原理
TLP250H,TLP250H(D4-TP1,F)是SOP8封装中的光电耦合器,由GaA组成ℓ作为红外发光二极管(LED)光学耦合到集成的高增益、高速光电探测器IC芯片。它在高达125℃的温度下提供有保证的性能和规格. TLP250H具有内部法拉第屏蔽,…...
Vue - Syntax Error: TypeError: this.getOptions is not a function 项目运行时报错,详细解决方案
报错问题 关于此问题网上的教程都无法解决,如果您的报错与本文相似,本文即可 100% 完美解决。 在 vue2.js 项目中,执行 npm run serve 运行时出现如下报错信息, Syntax Error: TypeError: this.getOptions is not a function 解决方案 按照以下步骤,即可完美解决。 这个错…...
C 语言类型转换
C 语言类型转换 类型转换允许我们将一种数据类型转换为另一种数据类型。在C语言中,我们使用强制转换运算符进行类型转换,用(type)表示。 语法: (type)value;注意:始终建议将较低的值转换为较高的值&…...
数据结构-链表的简单操作实现
目录 0.链表前序工作 1.构建出一个链表 2.展示链表中的所有存储数据 3.查找关键字key是否在链表中 4.求链表的长度 5.头插法 6.尾插法 7.插入任意位置(规定第一个元素位置为0下标) 8.删除第一次出现的值为key的关键字 9.删除所有值为key的关键字…...
竞赛选题 深度学习手势识别 - yolo python opencv cnn 机器视觉
文章目录 0 前言1 课题背景2 卷积神经网络2.1卷积层2.2 池化层2.3 激活函数2.4 全连接层2.5 使用tensorflow中keras模块实现卷积神经网络 3 YOLOV53.1 网络架构图3.2 输入端3.3 基准网络3.4 Neck网络3.5 Head输出层 4 数据集准备4.1 数据标注简介4.2 数据保存 5 模型训练5.1 修…...
【算法练习Day42】买卖股票的最佳时机 III买卖股票的最佳时机 IV
📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:练题 🎯长路漫漫浩浩,万事皆有期待 文章目录 买卖股票的最佳时机 III买卖…...
苹果手机如何备份通讯录?看完这篇就懂了!
如果遇到手机丢失或者出现故障的情况,通讯录备份可以避免联系人信息丢失。另外,当用户更换手机或者进行数据迁移时,提前备份好的通讯录数据可以快速还原到新设备上,避免了手动输入联系人的麻烦。苹果手机如何备份通讯录࿱…...
[yarn]yarn异常
一、运行一下算圆周率的测试代码,看下报错 cd /home/data_warehouse/module/hadoop-3.1.3/share/hadoop/mapreduce hadoop jar hadoop-mapreduce-examples-3.1.3.jar pi 1000 1000 后面2个数字参数的含义: 第1个1000指的是要运行1000次map任务 …...
C++ NULL 与nullptr 区别
在编写C程序的时候只看到过NULL,而在C的编程中,我们可以看到NULL和nullptr两种关键字,其实nullptr是C11版本中新加入的,它的出现是为了解决NULL表示空指针在C中具有二义性的问题。 一、C程序中的NULL 在C语言中,NULL…...
Google Chrome 浏览器 119.0.6045.106 版本提示 STATUS_INVALID_IMAGE_HASH 崩溃
问题 今天更新 Google Chrome 浏览器到 119.0.6045.106 版本,然后访问页面不是空白,就是页面崩溃了 解决方案 我在网上找了几种,下面这个方式符合,能解决我的问题,就是在快捷方式的属性那里,找到目标给它…...
网络IO
网络IO 阻塞模型 在之前网络通信都是阻塞模型 客户端向服务端发出请求后,客户端会一直处于等待状态,直到服务器端返回结果或网络出现问题 服务器端也是如此,在处理某个客户端A发来的请求时,另一个客户端B发来的请求会等待…...
数据库管理-第115期 too many open files(202301107)
数据库管理-第115期 too many open files(202301107) 这是我上周末帮朋友站台过程中处理的一个问题。 1 背景 其实这是别人搭的一个使用CentOS 7.8系统安装的一套11.2.0.4(无补丁)的双节点RAC,用于迁移以前运行在So…...
一行命令让你的服务器命令行亮起来!!!!
if [ "$(whoami)" "root" ]; then echo "PS1${debian_chroot:($debian_chroot)}\[\033[01;32m\]\u\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]# " >> /root/.bashrc; source /root/.bashrc; echo "已为root用户设置提示符以#结尾…...
线性代数(二)| 行列式性质 求值 特殊行列式 加边法 归纳法等多种方法
文章目录 1. 性质1.1 重要性质梳理1.1.1 转置和初等变换1.1.2加法行列式可拆分1.1.3 乘积行列式可拆分 1.2 行列式性质的应用1.2.1 简化运算1.2.2 将行列式转换为(二)中的特殊行列式 2 特殊行列式2.1 上三角或下三角行列式2.2 三叉行列式2.3 行列式行和&…...
OpenCV入门7:图像形态学变换
形态学是一种针对图像形状和结构进行操作和分析的图像处理方法。在OpenCV中,提供了一些函数和方法用于执行形态学操作。下面将介绍一些常见的形态学操作及其在OpenCV中的实现方式。 膨胀(Dilation): 膨胀操作可以扩展图像中的边…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
图表类系列各种样式PPT模版分享
图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
