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. vue全家桶进阶之路13:生命周期

    Vue2的生命周期是指Vue实例从创建.挂载.更新.销毁等各个阶段中所经历的一系列过程.Vue2的生命周期共有8个阶段,分别是: beforeCreate:Vue实例被创建之前的阶段,此时Vue实例的 ...

  2. OpenAI 官宣首个 ChatGPT iOS 应用

    最近,OpenAI 宣布推出官方 iOS 应用,允许用户随时随地访问其高人气 AI 聊天机器人,此举也打破了近几个月内苹果 App Store 上充斥似是而非的山寨服务的窘境. 该应用程序是 Chat ...

  3. 2014年蓝桥杯C/C++大学B组省赛真题(切面条)

    题目描述: 一根高筋拉面,中间切一刀,可以得到2根面条. 如果先对折1次,中间切一刀,可以得到3根面条. 如果连续对折2次,中间切一刀,可以得到5根面条. 那么,连续对折10次,中间切一刀,会得到多少 ...

  4. 【模型部署 01】C++实现分类模型(以GoogLeNet为例)在OpenCV DNN、ONNXRuntime、TensorRT、OpenVINO上的推理部署

    深度学习领域常用的基于CPU/GPU的推理方式有OpenCV DNN.ONNXRuntime.TensorRT以及OpenVINO.这几种方式的推理过程可以统一用下图来概述.整体可分为模型初始化部分和 ...

  5. OSPF 多区域配置实验

    实验拓扑 实验需求 按照图示配置 IP 地址和loopback 接口 按照图示分区域配置 OSPF ,实现全网互通 为了路由结构稳定,要求路由器使用环回口作为 Router-id 在AR3上配置静默接 ...

  6. cmake 安装一个目录下的图片 到另一个目录文件中去

    install(DIRECTORY ./cfg/labels/ DESTINATION ./fservo/cfg/yolo_cfg/labels/) install (DIRECTORY ./cfg/ ...

  7. @FunctionalInterface注解的使用

    被@FunctionalInterface注解标记的类型表明这是一个函数接口.从概念上讲,函数接口只有一个抽象方法.如果接口声明的抽象方法覆写Object类的公共方法,那这方法不算作接口的抽象方法,因 ...

  8. GPT3的应用场景:从文本生成到智能推荐

    目录 1. 引言 2. 技术原理及概念 2.1 基本概念解释 2.2 技术原理介绍 2.3 相关技术比较 3. 实现步骤与流程 3.1 准备工作:环境配置与依赖安装 3.2 核心模块实现 3.3 集成 ...

  9. HLS AES加密

    HLS AES加密 HLS AES加密介绍 HLS AES加密是一种用于保护HLS流内容安全的加密技术.它通过将HLS媒体文件进行分段,并使用AES加密算法对每个片段进行加密,从而防止未经授权的访问和 ...

  10. Unity iOS Guideline 1.3 - Safety - Kids Category 被拒

    解决办法: 不使用unity 的分析SDK //关闭unity信息收集服务 UnityEngine.Analytics.Analytics.enabled = false; UnityEngine.A ...