Spring Boot应用使用GraalVM本地编译相关配置
1. 介绍
Java应用程序可以通过Graalvm Native Image提前编译生成与本地机器相关的可执行文件。与在JVM执行java程序相比,Native Image占用内存更小和启动速度更快。
从spring boot3开始支持GraalVM Native Image,因此要使用此特性,需要把spring boot升级到3.0.0以上, 其中,JDK也要升级到17以上。
官方提供的示例见Developing Your First GraalVM Native Application。示例代码与普通spring boot一样,可以忽略,继续看下面内容。
1.1 maven插件配置
示例中与spring boot项目一样,不同之处在于打包配置,比如maven pom.xml文件中需要加上graalvm的native-maven-plugin
插件,如下:
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.0</version><relativePath/>
</parent><!--省略--><dependencies>
<!--省略-->
</dependencies><build><plugins><plugin><groupId>org.graalvm.buildtools</groupId><artifactId>native-maven-plugin</artifactId></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><!--其它插件--></plugins>
</build>
pom说明:<parent>
项指定为spring-boot-starter-parent
,这样你就可以减少许多配置,就像上面一样。
在spring-boot-starter-parent
中为生成Native Image定义了名为native
的profile,打包生成可执行文件使用如下maven命令
mvn clean package -Pnative
1.2 maven插件完整配置
如果pom的<parent>
项不是spring-boot-starter-parent
,你就需要像如下配置
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-jar-plugin</artifactId><version>3.3.0</version><configuration><archive><manifestEntries><Spring-Boot-Native-Processed>true</Spring-Boot-Native-Processed></manifestEntries></archive></configuration>
</plugin>
<plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>3.3.0</version><configuration><image><builder>paketobuildpacks/builder-jammy-tiny:latest</builder><env><BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE></env></image></configuration><executions><execution><id>process-aot</id><goals><goal>process-aot</goal></goals></execution></executions>
</plugin>
<plugin><groupId>org.graalvm.buildtools</groupId><artifactId>native-maven-plugin</artifactId><version>0.10.2</version><configuration><classesDirectory>${project.build.outputDirectory}</classesDirectory></configuration><executions><execution><id>add-reachability-metadata</id><goals><goal>add-reachability-metadata</goal></goals></execution></executions>
</plugin>
2. 开发注意事项
Spring Boot对自身提供的bean自动注入、AOP配置、factories等特性做了Native支持,在静态编译期间相关类都可达,
但我们的项目中还有些不受spring AOT支持的代码,比如业务代码中的反射、JSON和对象转换、以及三方jar包中动态代码等。
我们需要手动配置提供hint,graalvm才能把这些动态代码编译到可执行文件中去,否则执行时会抛出异常。
2.1 项目中动态代码支持
提供动态代码的hint配置,有三种方式:
- 第一种遵从graalvm规范提供相应的json配置,这个可以见往期分享Graalvm配置文件与Feature和Substitute机制介绍
- 第二种扩展Spring接口,即实现
RuntimeHintsRegistrar
接口,通过代码指定哪些类、资源需要hint。 - 第三种反射类可以使用
@RegisterReflectionForBinding
由spring自动绑定反射配置。
下面介绍后面两种方式
2.1.1 扩展Spring接口RuntimeHintsRegistrar
- 示例代码如下:
public class MyAOTRuntimeHints implements RuntimeHintsRegistrar {@Overridepublic void registerHints(RuntimeHints hints, ClassLoader classLoader) {// Register method for reflection// Method method = ReflectionUtils.findMethod(MyClass.class, "sayHello", String.class);// hints.reflection().registerMethod(method, ExecutableMode.INVOKE);// 反射注册hints.reflection().registerType(UserModel.class, typeHint -> {typeHint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,MemberCategory.INVOKE_DECLARED_METHODS,MemberCategory.DECLARED_FIELDS);});// 资源文件注册hints.resources().registerPattern("resource_hint.properties");// Serialization类注册hints.serialization().registerType(Email.class);// 代理注册// hints.proxies().registerJdkProxy(MyInterface.class);} }
- 注册Hint类。MyAOTRuntimeHints还需要使用
@ImportRuntimeHints
注解到任何@Configuration
class,或者在META-INF/aot.factories
文件注册- 使用
@ImportRuntimeHints
@Configuration @ImportRuntimeHints(value = {MyAOTRuntimeHints.class}) public class AOTConfiguration {}
- 注册
META-INF/aot.factories
org.springframework.aot.hint.RuntimeHintsRegistrar=com.example.springnative.aot.hit.MyAOTRuntimeHints
- 使用
2.1.2 使用注解@RegisterReflectionForBinding
对于项目中使用反射的地方,可以直接通过注解来配置hint,把@RegisterReflectionForBinding
注解到任何@Configuration
class类上。
示例如下:
@Configuration
@RegisterReflectionForBinding(classes = {MyJSONBean.class})
public class AOTConfiguration {}
2.2 代码中隐式使用反射的地方
2.2.1 JSON
json工具推荐使用jackson,spring中也对其做了支持。
把对象转为json或把json转为对象,对象中所有类都要注册反射hint。
如UserModel在在reflect-config.json配置如下
{
"name": "com.example.springnative.model.UserModel",
"allPublicConstructors": true,
"allDeclaredFields": true,
"allPublicMethods": true
}
如果javabean实现了java.io.Serializable接口,可以在serialization-config.json中注册,示例如下。
{
"name": "com.example.springnative.model.UserModel"
}
2.3 Configuration Properties类嵌套
如果Properties类嵌套了其它类型,则必须要使用@NestedConfigurationProperty
注解,否则spring AOT没法识别到这个嵌套类,就不能为其注册反射hint。如下示例。
@ConfigurationProperties(prefix = "my.properties")
public class MyProperties {@NestedConfigurationPropertyprivate final Nested nested = new Nested();// getters / setters...
}public class Nested {private int number;// getters / setters...}
2.4 Native Image执行与JVM执行区别
- 应用程序类路径在生成时是固定的,不能更改。
- 没有延迟类加载,可执行文件中提供的所有内容都将在启动时加载到内存中。
- 应用程序中定义的Bean不能在运行时更改,即bean创建相关的条件配置在编译后就不能再更改。
如@Profile注解及类似配置不能更改,@ConditionalOnProperty中的条件值不能更改,即使更改也不会生效,因为bean已经创建了。
3. 原理简述
- Spring AOT Processor会启动应用main方法开始静态分析,并生成BeanDefinition对象,但不会创建bean
- 分析阶段不可达的代码将被忽略,不会编译到可执行文件中。
- 在编译前会生成java代码来创建BeanDefinition对象。源码存放到target/spring-aot/main/sources
- AOP原本在运行时动态生成的字节码,但在编译时就必须生成,动态字节码存放在target/spring-aot/main/classes
- Spring AOT Processor生成native需要的hint文件,存放到target/spring-aot/main/resources
- Spring boot把所有生成的文件都编译到jar包中,关于hint文件都放到jar包的
META-INF/native-image
目录下,graalvm静态编译时会获取该目录下的hint配置文件。
4. 官方文档阅读
Known GraalVM Native Image limitations
Testing GraalVM Native Images
Introducing GraalVM Native Images
5. 总结
- maven插件配置有两种方式,
- 一种是pom的parent指定为
spring-boot-starter-parent
后简单引入spring的spring-boot-maven-plugin
和graalvm的native-maven-plugin
插件 - 另一种是完整的配置spring的
spring-boot-maven-plugin
插件指定process-aot
目标,配置graalvm的native-maven-plugin
插件指定add-reachability-metadata
目标
- 一种是pom的parent指定为
- 动态代码需要由开发者指定hint配置,有3种方式:
- 使用graalvm原生支持的方式,在
META-INF/native-image
目录下添加反射、代理、JNI等相关json配置。 - 实现
RuntimeHintsRegistrar
接口通过代码方式注册hint配置。 - 反射类可以使用
@RegisterReflectionForBinding
由spring自动绑定反射配置。
- 使用graalvm原生支持的方式,在
- 编译后影响bean创建相关的配置在运行期间不起作用,如
@ConditionalOnProperty
中的条件。
相关文章:
Spring Boot应用使用GraalVM本地编译相关配置
1. 介绍 Java应用程序可以通过Graalvm Native Image提前编译生成与本地机器相关的可执行文件。与在JVM执行java程序相比,Native Image占用内存更小和启动速度更快。 从spring boot3开始支持GraalVM Native Image,因此要使用此特性,需要把sp…...
代码的坏味道——长函数
前言:一个函数应该尽量做一件事情,如果非要做多个事情,要做函数提取,每次迭代应该考虑到是否有重复代码或者可以优化的代码。 长函数:长函数的产生: 逻辑是平铺直叙的需求迭代没有考虑优化,一次…...

【机器学习】基于密度的聚类算法:DBSCAN详解
🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 💫个人格言: "如无必要,勿增实体" 文章目录 基于密度的聚类算法:DBSCAN详解引言DBSCAN的基本概念点的分类聚类过…...

Qt 网络编程 网络信息获取操作
学习目标:网络信息获取操作 前置环境 运行环境:qt creator 4.12 学习内容 一、Qt 网络编程基础 Qt 直接提供了网络编程模块,包括基于 TCP/IP 的客户端和服务器相关类,如 QTcpSocket/QTcpServer 和 QUdpSocket,以及实现 HTTP、FTP 等协议的高级类,如 QNetworkRe…...

linux中的进程以及进程管理
程序和进程的区别和联系 程序(Program): 程序是一组指令的集合,通常存储在磁盘或其他存储设备上,是一种静态的概念。程序本身并没有运行,它只是一个可执行的文件或脚本,包含了一系列的指令和数…...
pyecharts可视化案例大全(11~20)
pyecharts可视化案例大全(11~20) 十一、设置动画效果十二、直方图带视觉组件十三、设置渐变色(线性渐变)十四、设置渐变色(径向渐变)十五、设置分割线十六、设置分隔区域十七、面积图十八、堆叠面积图十九、自定义线样式二十、折线图平滑处理十一、设置动画效果 在图表加载前…...
Docker在人工智能领域的应用与实战
摘要 人工智能(AI)技术的快速发展带来了对高效开发和部署工具的需求。Docker作为一个创新的容器化平台,为AI领域提供了强大的支持。本文详细介绍了Docker在AI模型开发、训练、部署以及服务器集群管理等方面的应用,并探讨了其在数…...

python基础篇(8):异常处理
在Python编程中,异常是程序运行时发生的错误,它会中断程序的正常执行流程。异常处理机制使得程序能够捕获这些错误,并进行适当的处理,从而避免程序崩溃。 1 错误类型 代码的错误一般会有语法错误和异常错误两种,语法错…...
FortiClient 用IPsec VPN 远程拨号到FortiGate说明文档
说明:本文档针对IPsec VPN 中的Remote VPN 进行说明,即远程用户使用PC中的FortiClient软件,通过VPN拨号的方式连接到公司总部FortiGate设备,访问公司内部服务器。在配置之前需要统一VPN策略和参数,如模式… 说明&#…...

Git-Unity项目版本管理
目录 准备GitHub新建项目并添加ssh密钥Unity文件夹 本文记录如何用git对unity 项目进行版本管理,并可传至GitHub远端。 准备 名称版本windows11Unity2202.3.9.f1gitN.A.githubN.A. GitHub新建项目并添加ssh密钥 GitHub新建一个repositorywindows11 生成ssh-key&…...

每日一题~ leetcode 402 (贪心+单调栈)
click me! 这个贪心的推导在leetcode上已经很明确了。 click me! 删除k个数,可以先考虑删除一个数。这也是一种常见的思路。(如果进行同样的操作多次,可以先只 考虑一次操作如何实现,或者他的影响。完成这一次操作后,…...

设计模式之模版方法
模版方法介绍 模版方法(Template Method)模式是一种行为型设计模式,它定义了一个操作(模板方法)的基本组合与控制流程,将一些步骤(抽象方法)推迟到子类中,使得子类可以在…...

docker部署redis/mongodb/
一、redis 创建/root/redis/conf/redis.conf 全部执行命令如下 docker run -it -d --name redis -p 6379:6379 --net mynet --ip 172.18.0.9 -m 400m -v /root/redis/conf:/usr/local/etc/redis -e TXAsia/Shangehai redis redis-server /usr/local/etc/redis/redis.conf 部署…...
LeetCode 581. 最短无序连续子数组
更多题解尽在 https://sugar.matrixlab.dev/algorithm 每日更新。 组队打卡,更多解法等你一起来参与哦! LeetCode 581. 最短无序连续子数组,难度中等。 排序 解题思路:首先对数组排序,然后找出两侧顺序的数组&#x…...

数据库可视化管理工具dbeaver试用及问题处理。
本文记录了在内网离线安装数据库可视化管理工具dbeaver的过程和相关问题处理方法。 一、下载dbeaver https://dbeaver.io/download/ 笔者测试时Windows平台最新版本为:dbeaver-ce-24.1.1-x86_64-setup.exe 二、安装方法 一路“下一步”即可 三、问题处理 1、问…...
29、php实现和为S的两个数字(含源码)
题目:php 实现 和为S的两个数字 描述: 输入一个递增排序的数组和一个数字S,在数组中查找两个数, 是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。 输出描述: 对应每个测…...
Spring Boot中的全局异常处理
Spring Boot中的全局异常处理 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将探讨如何在Spring Boot应用中实现全局异常处理,这是保证应用…...

中英双语介绍美国苹果公司(Apple Inc.)
中文版 苹果公司简介 苹果公司(Apple Inc.)是一家美国跨国科技公司,总部位于加利福尼亚州库比蒂诺。作为全球最有影响力的科技公司之一,苹果以其创新的产品和设计引领了多个科技领域的变革。以下是对苹果公司发展历史、主要产品…...
C语言牢大坠机
目录 开头程序程序的流程图《牢大坠机》结尾 开头 大家好,我叫这是我58,今天,我们要来看关于牢大坠机的一些东西。 程序 #define _CRT_SECURE_NO_WARNINGS 1 #define HIGH 66 #include <stdio.h> #include <Windows.h> int ma…...
zdppy+vue3+antd 实现表格单元格编辑功能
初步实现 <template><a-button class"editable-add-btn" style"margin-bottom: 8px" click"handleAdd">Add</a-button><a-table bordered :data-source"dataSource" :columns"columns"><templa…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...

23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...
华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)
题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...