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. 【Java】JTable的数据刷新

    前言 这段时间在写一个大实验,水果超市管理系统,yes,我觉得挺大的,但是就当成了一个实验,接下来还有一个课程设计和一个实训,more bigger... 问题 在我把其他的都写好的时候去写UI层,发 ...

  2. Django自定义storage上传文件到Minio

    首先新建一个MyStorage.py,自定义Storage类 from io import BytesIO from django.core.files.storage import Storage ...

  3. Kubernetes 证书详解

    K8S 证书介绍 在 Kube-apiserver 中提供了很多认证方式,其中最常用的就是 TLS 认证,当然也有 BootstrapToken,BasicAuth 认证等,只要有一个认证通过,那么 ...

  4. MassTransit类库Saga文档翻译

    翻译自 Saga State Machines Saga State Machines(状态机) Saga State Machines(状态机)以前被称为Automatonymous,从v8开始被合 ...

  5. 一篇文章带你详细了解axios的封装

    axios 封装 对请求的封装在实际项目中是十分必要的,它可以让我们统一处理 http 请求.比如做一些拦截,处理一些错误等.本篇文章将详细介绍如何封装 axios 请求,具体实现的功能如下 基本配置 ...

  6. 【LeetCode.384打乱数组】Knuth洗牌算法详解

    前两天看网易面筋得知网易云的随机歌曲播放使用了这个算法,遂找题来做做学习一下 打乱数组 https://leetcode.cn/problems/shuffle-an-array/ 给你一个整数数组 ...

  7. 前端学习C语言 - 第二篇(常量、运算符、控制和循环)

    常量.运算符.控制和循环 前文我们写了第一个 c 语言程序,了解了基本的数据类型.本篇将继续学习:常量.运算符.控制语句和循环语句. 常量 #define 常量 #define是用来定义常量和宏的预处 ...

  8. ChatGPT使用案例,助你快速上手,做事事半功倍

    ChatGPT介绍 首先我们来看一下chat-gpt自己的介绍: ChatGPT的发展历程 2015年,OpenAI成立,致力于研究和开发人工智能技术.在成立初期,OpenAI的创始人之一Elon M ...

  9. 前端Vue自定义加载中loading加载结束end组件 可用于分页展示 页面加载请求

    前端Vue自定义加载中loading加载结束end组件 可用于分页展示 页面加载请求, 请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id=132 ...

  10. 为什么从 MVC 到 DDD,架构的本质是什么?

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 本文来自于小傅哥新编写的<Java简明教程>系列内容,本教程意在于通过简单.明了. ...