以 Native 的方式运行 Java 程序
介绍
Java 由于其机制, 其 Java 程序通常都是由 JVM 来解释运行, 所以运行 Java 程序必须使用 java -jar
或其他命令来运行, 而不能在没有 JVM 的情况下运行
通过 GraalVM 可以使用 native-image
命令将 Java 的 class, module, jar 编译成一个二进制 native 程序, 从而可以不需要 JVM 直接运行
操作方法
官方文档: https://www.graalvm.org/latest/guides/
下载 GraalVM
社区版 GraalVM JDK: https://www.oracle.com/java/technologies/downloads/#graalvmjava21
和正常的 JDK 一样的使用方式
使用工具生成配置
由于 Java 的动态代理, 反射是在运行中确定的, native-image
是基于静态分析的, 所以必须提前告知其反射等信息
使用 java -agentlib
来生成配置文件
例如在当前目录下, 生成 demon.jar 的配置文件:
java -agentlib:native-image-agent=config-output-dir=./config -jar demo.jar
实际上他是把你的程序运行一遍分析
生成后的文件如下:
config
├── jni-config.json
├── predefined-classes-config.json
├── proxy-config.json
├── reflect-config.json
├── resource-config.json
└── serialization-config.json
将这些文件全部复制到项目的 resources/META-INF/org.example/demo 下 (注意换成你自己的包名)
复制后的文件结构如下:
native-demo
├── build.gradle.kts
└── src
├── main
├── java
│ └── org
│ └── example
│ └── demo
│ ├── Main.java
└── resources
└── META-INF
└── native-image
└── org.example
└── demo
├── jni-config.json
├── predefined-classes-config.json
├── proxy-config.json
├── reflect-config.json
├── resource-config.json
└── serialization-config.json
命令行编译
在完成上一步后重新打包 jar
使用 native-image -jar
编译 jar
native-image -jar demo.jar
编译完成就可以得到一个可运行的二进制文件了
构建工具编译
gradle
官方文档: https://graalvm.github.io/native-build-tools/latest/gradle-plugin.html
此处使用 KotlinDSL
首先添加插件
plugins {
id("org.graalvm.buildtools.native") version "0.10.1"
}
添加配置
graalvmNative {
binaries {
named("main") {
imageName.set("demo")
mainClass.set("org.example.demo.Main")
useFatJar.set(true)
}
}
binaries.all {
buildArgs.add("--verbose")
}
}
添加完成之后就可以使用 gradle nativeCompile
编译, 并且可以使用 gradle nativeRun
直接运行
maven
与 gradle 类似
官方文档: https://graalvm.github.io/native-build-tools/latest/maven-plugin.html
注意事项
- 编译运行后提示 "ClassNotFound" 一般是反射配置问题
- 编译运行后提示 "UnsupportedFeature" 可能是你使用了某些不兼容的库, 比如 log4j2
- 社区版为 Serial GC, 需要细心配置 vm 选项