我正在尝试使用 maven 插件创建 GraalVM 本机映像,但遇到了一些问题。
Here the config for the maven plugin
我正在使用 GraalVM JDK(通过 Sdkman 安装):
$ java -version
openjdk version "16.0.1" 2021-04-20
OpenJDK Runtime Environment GraalVM CE 21.1.0 (build 16.0.1+9-jvmci-21.1-b05)
OpenJDK 64-Bit Server VM GraalVM CE 21.1.0 (build 16.0.1+9-jvmci-21.1-b05, mixed mode, sharing)
我有一个简单的主类,例如:
package it.r;
public class Main {
public static void main(String[] args) {
System.out.println("********");
System.out.println(Main.class.getConstructors().length);
System.out.println("********");
}
}
使用 mvn exec:java -Dexec.mainClass=it.r.Main
执行时,我得到以下结果:
********
1
********
但是在执行 mvn package
然后执行创建的可执行文件时,结果是:
********
0
********
为什么会这样?
Here the git repo to reproduce
这个问题似乎影响 Jackson 反序列化,因为在另一个例子中,我有一个来自 jackson 的错误,无法反序列化 yaml 文件,因为它找不到我的类的构造函数。
答案 0 :(得分:0)
需要注册使用反射的类才能将它们包含在构建的本机映像中,more info in the docs
答案 1 :(得分:0)
当 GraalVM 原生映像将您的应用程序构建为原生二进制文件时,它会静态分析您的应用程序。
分析是静态的,因此您的应用程序可能使用的几个动态功能需要显式配置,例如:
classloader.getResource()
)这个显式配置是作为json配置文件提供的,例如
您可以手动提供配置文件,但您也可以使用 javaagent which will record usages of features requiring configuration 运行您的应用程序。
简而言之,您可以像这样运行您的应用程序:
java -agentlib:native-image-agent=config-output-dir=/path/to/config-dir/
和练习使用您要配置的代码的代码路径。这很重要,因为跟踪代理只能记录它实际看到运行的代码的配置。
然后输出目录将包含一个json文件,例如看起来像这样:
[
{
"name":"StringCapitalizer",
"methods":[{"name":"capitalize","parameterTypes":["java.lang.String"] }]
},
{
"name":"StringReverser",
"methods":[{"name":"reverse","parameterTypes":["java.lang.String"] }]
}
该文件列出了需要包含在分析中的类以及需要访问的二进制结果及其成员。 手动创建相当简单但有点乏味,这就是为什么首选代理方法。
还有一个 programmatic way to configure classes and members be registered for reflection,但使用它意味着您需要在您的应用中包含对 GraalVM 代码的依赖。