我正试图使用maven插件创建GraalVM本机映像,但遇到了一些问题
这里是maven插件的配置
我使用的是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
********
为什么会发生这种情况?
这里的git回购再现
这个问题似乎影响了Jackson的反序列化,因为在另一个例子中,我从Jackson那里得到了一个错误,它无法反序列化yaml文件,因为它找不到我的类的构造函数。
当GraalVM本机映像将应用程序构建为本机二进制文件时,它会静态地分析应用程序。
分析是静态的,因此应用程序可能使用的几个动态功能需要显式配置,例如:
- 反射
- 序列化
- 方法句柄
- 使用资源(如
classloader.getResource()
( - JNI
此显式配置以json配置文件的形式提供,例如
您可以手动提供配置文件,但也可以使用javaagent运行应用程序,它将记录需要配置的功能的使用情况。
简而言之,您的应用程序是这样运行的:
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"] }]
}
该文件列出了需要包含在分析中的类以及需要访问的二进制结果及其成员。它相当简单,但手动创建有点乏味,这就是为什么首选代理方法的原因。
还有一种编程方式可以配置类和成员以进行反射注册,但使用它意味着你需要在应用程序中包含对GraalVM代码的依赖。
需要注册使用反射的类,以便将它们包含在构建的本地映像中,更多信息请参阅文档