[超详细] GraalVM打包含有JNI的本地镜像
GraalVM 是一种高性能、多语言通用虚拟机和编译器技术。它由 Oracle 开发并开源,旨在为不同的编程语言和应用场景提供统一的运行时环境和编译器平台。以下是 GraalVM 的一些主要特点和功能:
- 多语言支持: GraalVM 支持多种编程语言,包括 Java、JavaScript(Node.js)、Python、Ruby、R、C 和 C++ 等。这使得开发者可以在同一平台上运行不同语言的代码,从而降低了开发和部署的复杂性。
- 高性能 JIT 编译器: GraalVM 包含了一款高性能的即时编译器,可以将 Java 代码编译成高效的本地机器码,从而提供更快的执行速度和较低的内存占用。
- AOT 编译: GraalVM 还支持 AOT(Ahead-Of-Time)编译,可以将 Java 代码编译成本地可执行文件,无需依赖 JVM。这有助于提高启动速度和减少内存消耗。
- 本地图像生成: GraalVM 的本地图像功能可以将 Java 应用程序和依赖项一起打包成本地可执行文件,无需 JVM。这有助于简化部署,并减少应用程序的启动时间和资源占用。
- JIT 监控和分析: GraalVM 提供了丰富的监控和分析工具,可以帮助开发者了解 JIT 编译的情况,优化代码性能,以及识别潜在的性能瓶颈。
- 多语言互操作性: GraalVM 支持在不同语言之间进行互操作,例如在 Java 代码中调用 JavaScript 函数,或在 JavaScript 代码中调用 Java 类。
- 支持 WebAssembly: GraalVM 可以将 Java 代码编译成 WebAssembly 格式,使得 Java 应用程序可以在浏览器中运行。
- 开放源代码: GraalVM 是一个开放源代码项目,您可以在 GitHub 上找到它的源代码和文档。
GraalVM 在加速 Java 应用程序、支持多语言开发、优化资源使用等方面提供了一系列创新功能。它被广泛用于构建高性能的应用程序、微服务、嵌入式系统以及各种语言的运行时环境。
注意:
- GraalVM暂不支持交叉编译,只能编译本平台的可执行文件。
- 使用native-image工具进行本地编译可能会限制应用程序的一些动态特性和反射能力,因为GraalVM的AOT编译需要在编译时了解所有可能的代码路径。在某些情况下,可能需要对应用程序的代码进行调整,以便与GraalVM的编译要求相匹配。
- SpringBoot在3.0版本拥有Sprng Native特性,支持GraalVM打包。
1 安装GraalVM环境(以Windows为例)
1.1 下载GRaalVM JDK
https://www.graalvm.org/downloads/

1.2 配置GraalVM环境变量
将JAVA_HOME配置到该层目录下


并将JAVA_HOME的/bin添加到PATH中。(不用管这里的jre/bin,我只是偷懒不想换)

打开命令行,输入以下命令,看是否配置环境变量成功

2 安装 Visual Studio
2.1 下载 Visual Studio
https://visualstudio.microsoft.com/zh-hans/
打开Visual Studio Installer,选择使用C++的桌面开发,并如图选择组件。

2.2 配置Visual Studio环境变量
添加以下三个环境变量
INCLUDE=C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\ucrt;C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\shared;D:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.16.27023\include.;
LIB=C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17134.0\um\x64;C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17134.0\ucrt\x64;D:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.16.27023\lib\x64;
PATH=%PATH%;D:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.16.27023\bin\HostX64\x64
3 编写Java程序
由于GraalVM对于反射的支持不是很好,所以要为JNI的操作类写配置文件。在项目中创建jniconfig,该文件是json格式的文件,用来描述JNI数据交换类的。你的JNI程序是用哪个类交换数据,那你就需要为这个类编写这个配置文件,否则GraalVM的本地镜像不能正常运行。示例如下图,fields是属性,methods是方法,name是路径变量名。
[
{
"name" : "com.cInterface.Data",
"queryAllDeclaredConstructors" : true,
"queryAllPublicConstructors" : true,
"queryAllDeclaredMethods" : true,
"queryAllPublicMethods" : true,
"allDeclaredClasses" : true,
"allPublicClasses" : true
},
{
"name" : "com.cInterface.Data",
"fields" : [
{ "name" : "mParam" },
{ "name" : "mInfo" }
],
"methods" : [
{ "name" : "<init>", "parameterTypes" : [] },
{ "name" : "getParam", "parameterTypes" : [] },
{ "name" : "setInfo", "parameterTypes" : ["byte[]", "int"] }
]
}
]
3.1 编写pom.xml文件
注意:你需要知道你引入的项目依赖是否支持GraalVM,否则可能会出现不可预知的问题。
在pom.xml你主要做的事情是
- 设置依赖版本(SpringBoot从3.0版本开始支持GraalVM)
- 指定JDK版本(你下载的GraalVM是什么版本就指定什么java.version)
- 设置GraalVM打包插件
pom.xml附在文章的最后面
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<configuration>
<!-- imageName用于设置生成的二进制文件名称 -->
<imageName>${project.artifactId}</imageName>
<!-- mainClass用于指定main方法类路径 -->
<mainClass>com.xxx.Application</mainClass>
<buildArgs>
<!-- 这些配置类基本都是指定初始化时间和一些配置,都不用管,并且不要动,否则可能会打包失败 -->
--no-fallback
--initialize-at-build-time=org.springframework.util.unit.DataSize
--initialize-at-build-time=org.slf4j.MDC
--initialize-at-build-time=ch.qos.logback.classic.Level
--initialize-at-build-time=ch.qos.logback.classic.Logger
--initialize-at-build-time=ch.qos.logback.core.util.StatusPrinter
--initialize-at-build-time=ch.qos.logback.core.status.StatusBase
--initialize-at-build-time=ch.qos.logback.core.status.InfoStatus
--initialize-at-build-time=ch.qos.logback.core.spi.AppenderAttachableImpl
--initialize-at-build-time=org.slf4j.LoggerFactory
--initialize-at-build-time=ch.qos.logback.core.util.Loader
--initialize-at-build-time=org.slf4j.impl.StaticLoggerBinder
--initialize-at-build-time=ch.qos.logback.classic.spi.ThrowableProxy
--initialize-at-build-time=ch.qos.logback.core.CoreConstants
--report-unsupported-elements-at-runtime
--allow-incomplete-classpath
-H:+ReportExceptionStackTraces
<!-- 指定刚刚编写的jniconfig路径,我这里比较懒,就直接放在pom.xml相同路径下 -->
-H:JNIConfigurationFiles=jniconfig
</buildArgs>
</configuration>
</plugin>
3.2 打包本地镜像
打开命令行工具,注意是打开这个,不是cmd或者powershell。因为cmd和powershell有命令长度限制,必须使用这个进行命令行操作。

cd到项目的pom.xml文件夹下,输入以下命令进行打包。-Pnative是指定打包成本地镜像,-DskipTests是跳过测试。
mvn -Pnative -DskipTests native:compile
稍等一会,看到以下信息即为打包成功。

3.3 运行本地镜像
打包完成后,项目根路径会有一个target文件夹,里面有个exe文件和awt.dll、java.dll、jwm.dll文件。这就是项目运行的全部文件了。
注意:若你的项目为JNI项目,请把你预先编译好的dll文件放到exe同路径下,或放到
java.library.path路径上,否则项目无法正常运行。
4 GraalVM打包本地镜像的好处
GraalVM 的本地镜像打包功能可以将 Java 应用程序及其依赖项打包成本地可执行文件,无需依赖 JVM,从而带来许多好处:
- 快速启动: 传统的 Java 应用程序需要加载 JVM 和运行时库,因此启动时间可能较长。而使用 GraalVM 本地镜像,应用程序可以直接运行在本地机器码上,启动时间大幅缩短,适用于需要快速启动的场景,如命令行工具和无服务器应用。
- 内存占用减少: 传统的 Java 应用程序需要一定的内存来容纳 JVM 和运行时库。使用 GraalVM 本地镜像,应用程序仅加载所需的代码和依赖项,可以显著减少内存占用,有助于优化资源使用。
- 单一分发文件: 本地镜像将应用程序及其所有依赖项打包成一个可执行文件,便于分发和部署。这消除了对于目标系统是否已安装特定版本的 JVM 的依赖,简化了部署过程。
- 减少依赖: GraalVM 本地镜像中已经包含了应用程序的依赖项,因此无需手动安装和配置额外的依赖库。
- 更轻量级: 本地镜像只包含应用程序和依赖项的精简版本,因此文件大小较小,减少了磁盘空间的使用。
- 无需 JVM 安装: 使用 GraalVM 本地镜像运行 Java 应用程序无需安装 JVM,这对于在容器化环境中运行应用程序非常有用,可以减小容器的镜像大小。
- 与云原生技术兼容: 本地镜像适用于云原生技术栈,如容器化和无服务器架构,能够更好地满足现代应用开发的需求。
GraalVM 的本地镜像打包功能为 Java 应用程序提供了更快的启动时间、更低的内存占用、更轻量级的分发文件等优势,适用于多种场景,特别是对于需要快速启动和优化资源的应用程序。
5 附录
pom.xml文件
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.2</version>
<relativePath />
</parent>
<groupId>com.xxx</groupId>
<artifactId>application</artifactId>
<version>1.0.1-SNAPSHOT</version>
<name>Application</name>
<url>https://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- springboot-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.1.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<configuration>
<!-- imageName用于设置生成的二进制文件名称 -->
<imageName>${project.artifactId}</imageName>
<!-- mainClass用于指定main方法类路径 -->
<mainClass>com.xxx.Application</mainClass>
<buildArgs>
--no-fallback
--initialize-at-build-time=org.springframework.util.unit.DataSize
--initialize-at-build-time=org.slf4j.MDC
--initialize-at-build-time=ch.qos.logback.classic.Level
--initialize-at-build-time=ch.qos.logback.classic.Logger
--initialize-at-build-time=ch.qos.logback.core.util.StatusPrinter
--initialize-at-build-time=ch.qos.logback.core.status.StatusBase
--initialize-at-build-time=ch.qos.logback.core.status.InfoStatus
--initialize-at-build-time=ch.qos.logback.core.spi.AppenderAttachableImpl
--initialize-at-build-time=org.slf4j.LoggerFactory
--initialize-at-build-time=ch.qos.logback.core.util.Loader
--initialize-at-build-time=org.slf4j.impl.StaticLoggerBinder
--initialize-at-build-time=ch.qos.logback.classic.spi.ThrowableProxy
--initialize-at-build-time=ch.qos.logback.core.CoreConstants
--report-unsupported-elements-at-runtime
--allow-incomplete-classpath
-H:+ReportExceptionStackTraces
-H:JNIConfigurationFiles=jniconfig
</buildArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
[超详细] GraalVM打包含有JNI的本地镜像的更多相关文章
- (超详细)使用git命令行将本地仓库代码上传到github或gitlab远程仓库
(超详细)使用git命令行将本地仓库代码上传到github或gitlab远程仓库 本地创建了一个 xcode 工程项目,现通过 命令行 将该项目上传到 github 或者 gitlab 远程仓库,具体 ...
- JAXB常用注解讲解(超详细)
简介: JAXB(Java Architecture for XML Binding) 是一个业界的标准,是一项可以根据XML Schema产生Java类的技术.该过程中,JAXB也提供了将XML实例 ...
- 【强烈推荐,超详细,实操零失误】node.js安装 + npm安装教程 + Vue开发环境搭建
node.js安装 + npm安装教程 + Vue开发环境搭建 [强烈推荐,超详细,实操零失误] 原博客园地址:https://www.cnblogs.com/goldlong/p/8027997.h ...
- JavaWeb和WebGIS学习笔记(七)——MapGuide Open Source安装、配置以及MapGuide Maestro发布地图——超详细!目前最保姆级的MapGuide上手指南!
JavaWeb和WebGIS学习笔记(七)--MapGuide Open Source安装.配置以及MapGuide Maestro发布地图 超详细!目前最保姆级的MapGuide上手指南! 系列链接 ...
- Github上传代码菜鸟超详细教程【转】
最近需要将课设代码上传到Github上,之前只是用来fork别人的代码. 这篇文章写得是windows下的使用方法. 第一步:创建Github新账户 第二步:新建仓库 第三部:填写名称,简介(可选), ...
- [转]超详细图解:自己架设NuGet服务器
本文转自:http://diaosbook.com/Post/2012/12/15/setup-private-nuget-server 超详细图解:自己架设NuGet服务器 汪宇杰 ...
- GitHub超详细图文攻略
GitHub超详细图文攻略 - Git客户端下载安装 GitHub提交修改源码工作流程 Git 分类: 转载2014-03-25 21:10 10641人阅读 评论(2) 收藏 举报 GitHubbr ...
- Linux 学习笔记之超详细基础linux命令(the end)
Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122 ---------------------------------接Part 14---------------- ...
- Linux 学习笔记之超详细基础linux命令 Part 14
Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122 ---------------------------------接Part 13---------------- ...
- 超详细!Github团队协作教程(Gitkraken版)
超详细!Github团队协作教程(Gitkraken版) 一.前期工作 1. 在 Github 上创建 organization step1. 登录Github网站,点击右上角头像,选择 " ...
随机推荐
- Node.js出现‘Cannot find module init’ 解决方法
1. 首先查看当前根目录是否有node_module文件夹,如果有,请删除 2. 输入 npm clean cache 3. 再次输入 node init -y 大功告成
- 一篇文章告诉你什么是Java内存模型
在上篇 并发编程Bug起源:可见性.有序性和原子性问题,介绍了操作系统为了提示运行速度,做了各种优化,同时也带来数据的并发问题, 定义 在单线程系统中,代码按照顺序从上往下顺序执行,执行不会出现问题. ...
- Spring源码:Bean生命周期(终章)
前言 本系列前面讲解了Spring的bean定义.bean实例化.bean初始化等生命周期.这些步骤使我们能够了解bean从创建到准备好使用所经历的过程.但是,除了这些步骤,bean的销毁也是非常重要 ...
- 【实践篇】手把手教你落地DDD
1. 前言 常见的DDD实现架构有很多种,如经典四层架构.六边形(适配器端口)架构.整洁架构(Clean Architecture).CQRS架构等.架构无优劣高下之分,只要熟练掌握就都是合适的架构. ...
- ir_ui_view: 字段 `group_display_incoterm` 不存在
ir_ui_view: 字段 `group_display_incoterm` 不存在 这种提示是没有这个字段, IR_UI_VIEW 模型存在这个视图: 1 可以登陆数据库,查询 SELECT * ...
- GTX.Zip:一款可以替代 gzip 的基因大数据压缩软件
今天给大家推荐一款基因大数据压缩的大杀器:GTX.Zip. GTX.Zip 这款软件是由曾在 2016 年 GCTA 风云挑战赛中的那匹黑马--人和未来生物科技有限公司开发的,而当时他们也是打破了基因 ...
- OSPF路由控制
实验拓扑 实验需求 公司A使用OSPF路由协议实现公司设备全网互通,后来公司A扩张兼并了公司B,要求将公司B采用的IS-IS路由协议与公司A的OSPF协议互相引入,使得相应部门可以实现互通. Rout ...
- 记一次BootCDN被黑产挂马导致站点跳转博彩网站的问题
近期发现公司某些站点出现偶尔跳转博彩网站的现象,经过排查发现该现象为供应链投毒攻击,BootCDN上的静态资源无一例外均被污染, 当外站引入BootCDN的静态资源时,如果请求携带的Referer头为 ...
- 稳,从数据库连接池 testOnBorrow 看架构设计
本文从 Commons DBCP testOnBorrow 的作用机制着手,管中窥豹,从一点去分析数据库连接池获取的过程以及架构分层设计. 以下内容会按照每层的作用,贯穿分析整个调用流程. 1️⃣框架 ...
- 前端Vue图片上传组件支持单个文件多个文件上传 自定义上传数量 预览删除图片 图片压缩
前端Vue图片上传组件支持单个文件多个文件上传 自定义上传数量 预览删除图片 图片压缩, 下载完整代码请访问uni-app插件市场址:https://ext.dcloud.net.cn/plugin? ...