GraalVM 是一种高性能、多语言通用虚拟机和编译器技术。它由 Oracle 开发并开源,旨在为不同的编程语言和应用场景提供统一的运行时环境和编译器平台。以下是 GraalVM 的一些主要特点和功能:

  1. 多语言支持: GraalVM 支持多种编程语言,包括 Java、JavaScript(Node.js)、Python、Ruby、R、C 和 C++ 等。这使得开发者可以在同一平台上运行不同语言的代码,从而降低了开发和部署的复杂性。
  2. 高性能 JIT 编译器: GraalVM 包含了一款高性能的即时编译器,可以将 Java 代码编译成高效的本地机器码,从而提供更快的执行速度和较低的内存占用。
  3. AOT 编译: GraalVM 还支持 AOT(Ahead-Of-Time)编译,可以将 Java 代码编译成本地可执行文件,无需依赖 JVM。这有助于提高启动速度和减少内存消耗。
  4. 本地图像生成: GraalVM 的本地图像功能可以将 Java 应用程序和依赖项一起打包成本地可执行文件,无需 JVM。这有助于简化部署,并减少应用程序的启动时间和资源占用。
  5. JIT 监控和分析: GraalVM 提供了丰富的监控和分析工具,可以帮助开发者了解 JIT 编译的情况,优化代码性能,以及识别潜在的性能瓶颈。
  6. 多语言互操作性: GraalVM 支持在不同语言之间进行互操作,例如在 Java 代码中调用 JavaScript 函数,或在 JavaScript 代码中调用 Java 类。
  7. 支持 WebAssembly: GraalVM 可以将 Java 代码编译成 WebAssembly 格式,使得 Java 应用程序可以在浏览器中运行。
  8. 开放源代码: GraalVM 是一个开放源代码项目,您可以在 GitHub 上找到它的源代码和文档。

GraalVM 在加速 Java 应用程序、支持多语言开发、优化资源使用等方面提供了一系列创新功能。它被广泛用于构建高性能的应用程序、微服务、嵌入式系统以及各种语言的运行时环境。

注意:

  1. GraalVM暂不支持交叉编译,只能编译本平台的可执行文件。
  2. 使用native-image工具进行本地编译可能会限制应用程序的一些动态特性和反射能力,因为GraalVM的AOT编译需要在编译时了解所有可能的代码路径。在某些情况下,可能需要对应用程序的代码进行调整,以便与GraalVM的编译要求相匹配。
  3. 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,从而带来许多好处:

  1. 快速启动: 传统的 Java 应用程序需要加载 JVM 和运行时库,因此启动时间可能较长。而使用 GraalVM 本地镜像,应用程序可以直接运行在本地机器码上,启动时间大幅缩短,适用于需要快速启动的场景,如命令行工具和无服务器应用。
  2. 内存占用减少: 传统的 Java 应用程序需要一定的内存来容纳 JVM 和运行时库。使用 GraalVM 本地镜像,应用程序仅加载所需的代码和依赖项,可以显著减少内存占用,有助于优化资源使用。
  3. 单一分发文件: 本地镜像将应用程序及其所有依赖项打包成一个可执行文件,便于分发和部署。这消除了对于目标系统是否已安装特定版本的 JVM 的依赖,简化了部署过程。
  4. 减少依赖: GraalVM 本地镜像中已经包含了应用程序的依赖项,因此无需手动安装和配置额外的依赖库。
  5. 更轻量级: 本地镜像只包含应用程序和依赖项的精简版本,因此文件大小较小,减少了磁盘空间的使用。
  6. 无需 JVM 安装: 使用 GraalVM 本地镜像运行 Java 应用程序无需安装 JVM,这对于在容器化环境中运行应用程序非常有用,可以减小容器的镜像大小。
  7. 与云原生技术兼容: 本地镜像适用于云原生技术栈,如容器化和无服务器架构,能够更好地满足现代应用开发的需求。

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的本地镜像的更多相关文章

  1. (超详细)使用git命令行将本地仓库代码上传到github或gitlab远程仓库

    (超详细)使用git命令行将本地仓库代码上传到github或gitlab远程仓库 本地创建了一个 xcode 工程项目,现通过 命令行 将该项目上传到 github 或者 gitlab 远程仓库,具体 ...

  2. JAXB常用注解讲解(超详细)

    简介: JAXB(Java Architecture for XML Binding) 是一个业界的标准,是一项可以根据XML Schema产生Java类的技术.该过程中,JAXB也提供了将XML实例 ...

  3. 【强烈推荐,超详细,实操零失误】node.js安装 + npm安装教程 + Vue开发环境搭建

    node.js安装 + npm安装教程 + Vue开发环境搭建 [强烈推荐,超详细,实操零失误] 原博客园地址:https://www.cnblogs.com/goldlong/p/8027997.h ...

  4. JavaWeb和WebGIS学习笔记(七)——MapGuide Open Source安装、配置以及MapGuide Maestro发布地图——超详细!目前最保姆级的MapGuide上手指南!

    JavaWeb和WebGIS学习笔记(七)--MapGuide Open Source安装.配置以及MapGuide Maestro发布地图 超详细!目前最保姆级的MapGuide上手指南! 系列链接 ...

  5. Github上传代码菜鸟超详细教程【转】

    最近需要将课设代码上传到Github上,之前只是用来fork别人的代码. 这篇文章写得是windows下的使用方法. 第一步:创建Github新账户 第二步:新建仓库 第三部:填写名称,简介(可选), ...

  6. [转]超详细图解:自己架设NuGet服务器

    本文转自:http://diaosbook.com/Post/2012/12/15/setup-private-nuget-server 超详细图解:自己架设NuGet服务器 汪宇杰          ...

  7. GitHub超详细图文攻略

    GitHub超详细图文攻略 - Git客户端下载安装 GitHub提交修改源码工作流程 Git 分类: 转载2014-03-25 21:10 10641人阅读 评论(2) 收藏 举报 GitHubbr ...

  8. Linux 学习笔记之超详细基础linux命令(the end)

    Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122 ---------------------------------接Part 14---------------- ...

  9. Linux 学习笔记之超详细基础linux命令 Part 14

    Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122 ---------------------------------接Part 13---------------- ...

  10. 超详细!Github团队协作教程(Gitkraken版)

    超详细!Github团队协作教程(Gitkraken版) 一.前期工作 1. 在 Github 上创建 organization step1. 登录Github网站,点击右上角头像,选择 " ...

随机推荐

  1. 2022-08-07:以下go语言代码输出什么?A:1 1;B:3 1;C:0 3;D:不能编译。 package main import ( “fmt“ “math“ ) func main

    2022-08-07:以下go语言代码输出什么?A:1 1:B:3 1:C:0 3:D:不能编译. package main import ( "fmt" "math&q ...

  2. 2022-01-26:最优账单平衡。 一群朋友在度假期间会相互借钱。比如说,小爱同学支付了小新同学的午餐共计 10 美元。如果小明同学支付了小爱同学的出租车钱共计 5 美元。我们可以用一个三元组 (x

    2022-01-26:最优账单平衡. 一群朋友在度假期间会相互借钱.比如说,小爱同学支付了小新同学的午餐共计 10 美元.如果小明同学支付了小爱同学的出租车钱共计 5 美元.我们可以用一个三元组 (x ...

  3. 3 分钟利用 FastGPT 和 Laf 将 ChatGPT 接入企业微信

    原文链接:https://forum.laf.run/d/556 FastGPT 是一个超级的 ChatGPT 平台项目,功能非常强大: 集成了 ChatGPT.GPT4 和 Claude 可以使用任 ...

  4. 2023 5.14 虚拟环境安装Linux

    1.安装配置VM虚拟机 vmare workstation 虚拟机是一款桌面计算机虚拟软件 让用户能够在单一主机上同事运行多个操作系统 1.每个虚拟操作系统的硬盘与数据都是独立 2.多台虚拟机可以构建 ...

  5. 【LeetCode双向链表】LRU详解,双向链表实战

    LRU缓存 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构. 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 capacity ...

  6. 【VS Code 与 Qt6】QCheckBox的图标为什么不会切换?

    本篇专门扯一下有关 QCheckBox 组件的一个问题.老周不水字数,直接上程序,你看了就明白. #include <QApplication> #include <QWidget& ...

  7. 基于Elasticsearch 为电商提供商品数据大数据查询

    基于Elasticsearch 为电商提供商品数据大数据查询 前言 对于现代电商的产品,维度的多员花,与一套强大的搜索引擎,那是非常必要的.今天我们主要是描述我们在从事电商搜索引擎过程中的遇到的一些问 ...

  8. git推送时被拒绝,发现class文件被人上传到仓库的解决办法

    写好的代码commit之后,想要推送到远端,结果发现有同事提交了class文件 这时候我们需要执行以下指令 git stash git pull git stash pop 原理:先把commit的东 ...

  9. Java使用数组存储成绩,输出成绩列表,总分,平均分

    代码如下: public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out. ...

  10. Linux系统运维之MYSQL数据库集群部署(主主互备)

    一.介绍 既然是部署MYSQL高可用集群环境,就要介绍下MYSQL Replication,MYSQL Replication是MYSQL自带的一个主从复制功能,也就是一台MYSQL服务器向另外一台M ...