使用graalvm为带有反射功能的java代码生成native image的示例详解

 更新时间:2024年02月09日 09:16:35   作者:心与梦  
graalvm让native镜像支持反射的关键是利用json提前告诉它哪些类的哪些方法会被反射调用,然后它就能力在运行时支持反射了,这篇文章主要介绍了如何使用graalvm为带有反射功能的java代码生成native image,需要的朋友可以参考下

译自Configure Native Image with the Tracing Agent graal官方文档 , 以下所有命令需要在linux环境下操作,graalvm也支持windows。

要为使用 Java 反射、动态代理对象、JNI 或类路径资源的 Java 应用程序构建本机可执行文件,应为 native-image 工具提供 JSON 格式的配置文件或在代码中预先计算元数据。

您可以手动创建配置文件,但更方便的方法是使用跟踪代理(即Tracing agent,下面用代理一词代称)生成配置。本指南演示如何使用代理进行配置 native-image 。当您在 JVM 上运行应用程序时,代理会自动为您生成配置。

若要了解如何使用代码中预先计算的元数据生成本机可执行文件,请参阅文档 - Reachability Metadata 可访问性元数据

本指南中的示例应用程序使用 Java 反射。该 native-image 工具仅部分检测使用 Java 反射 API 访问的应用程序元素。因此,您需要向它提供有关反射访问的类、方法和字段的详细信息。

不配置Json格式的反射信息示例

将以下源代码保存在名为 ReflectionExample.java 的文件中:

 import java.lang.reflect.Method;
 class StringReverser {
     static String reverse(String input) {
         return new StringBuilder(input).reverse().toString();
     }
 }
 class StringCapitalizer {
     static String capitalize(String input) {
         return input.toUpperCase();
     }
 }
 public class ReflectionExample {
     public static void main(String[] args) throws ReflectiveOperationException {
         if (args.length == 0) {
             System.err.println("You must provide the name of a class, the name of its method and input for the method");
             return;
         }
         String className = args[0];
         String methodName = args[1];
         String input = args[2];
         Class<?> clazz = Class.forName(className);
         Method method = clazz.getDeclaredMethod(methodName, String.class);
         Object result = method.invoke(null, input);
         System.out.println(result);
     }
 }

该Java 应用程序使用命令行参数来确定要执行的反射操作。

运行如下命令:

$JAVA_HOME/bin/javac ReflectionExample.java   # 编译
$JAVA_HOME/bin/java ReflectionExample StringReverser reverse "hello"   # 输出 olleh
$JAVA_HOME/bin/java ReflectionExample StringCapitalizer capitalize "hello"   # 输出 HELLO

使用 native-image 命令创建本机可执行文件,如下所示:

 $JAVA_HOME/bin/native-image --no-fallback ReflectionExample

使用以下命令运行生成的本机可执行文件:

./reflectionexample StringReverser reverse "hello"

您将看到一个异常,类似于:

 Exception in thread "main" java.lang.ClassNotFoundException: StringReverser
 at java.lang.Class.forName(DynamicHub.java:1338)
 at java.lang.Class.forName(DynamicHub.java:1313)
 at ReflectionExample.main(ReflectionExample.java:25)

这表明,根据静态分析,native-image 工具无法确定 StringReverser 类是否被使用,所以未将其包含在本机可执行文件中。

配置Json格式的反射信息示例

以下步骤演示如何使用代理及其输出来创建依赖于反射且需要配置的本机可执行文件。

在工作目录中创建名为 META-INF/native-image 的目录:

mkdir -p META-INF/native-image

在启用代理的情况下运行应用程序生成json配置,如下所示:

$JAVA_HOME/bin/java -agentlib:native-image-agent=config-output-dir=META-INF/native-image ReflectionExample StringReverser reverse "hello"

此命令创建一个名为 reflect-config.json 的文件,其中包含类 StringReverser 的名称及其 reverse() 方法。

 [
 {
 "name":"StringReverser",
 "methods":[{"name":"reverse","parameterTypes":["java.lang.String"] }]
 }
]

构建本机可执行文件:

$JAVA_HOME/bin/native-image ReflectionExample

native-image 工具会自动使用 META-INF/native-image 目录中的配置文件。但是,建议将 META-INF/native-image 目录放到类路径上,可以通过 JAR 文件或使用标志 -cp 。(这样可以避免 IDE 用户在目录结构由 IDE 本身定义时出现混淆。)

测试可执行文件

./reflectionexample StringReverser reverse "hello" # 输出 olleh
./reflectionexample StringCapitalizer capitalize "hello"

执行后会看到一个异常,类似于:

 Exception in thread "main" java.lang.ClassNotFoundException: StringCapitalizer
 at java.lang.Class.forName(DynamicHub.java:1338)
 at java.lang.Class.forName(DynamicHub.java:1313)
 at ReflectionExample.main(ReflectionExample.java:25)

跟踪代理和 native-image 工具都无法确保配置文件完整。当您运行程序时,代理会观察并记录使用反射访问了哪些程序元素。在这种情况下,该 native-image 工具尚未配置为包含对类 StringCapitalizer 的引用。

更新配置以包含类 StringCapitalizer 。您可以使用以下 config-merge-dir 选项手动编辑 reflect-config.json 文件或重新运行跟踪代理以更新现有配置文件,如下所示:

 $JAVA_HOME/bin/java -agentlib:native-image-agent=config-merge-dir=META-INF/native-image ReflectionExample StringCapitalizer capitalize "hello"

此命令更新 reflect-config.json 文件,以包含类 StringCapitalizer 的名称及其 capitalize() 方法。

 [
     {
     "name":"StringCapitalizer",
     "methods":[{"name":"capitalize","parameterTypes":["java.lang.String"] }]
     },
     {
     "name":"StringReverser",
     "methods":[{"name":"reverse","parameterTypes":["java.lang.String"] }]
     }
 ]

重新生成本机可执行文件并运行,不会有报错了。

 $JAVA_HOME/bin/native-image ReflectionExample
 ./reflectionexample StringCapitalizer capitalize "hello"

总结

graalvm让native镜像支持反射的关键是利用json提前告诉它哪些类的哪些方法会被反射调用,然后它就能力在运行时支持反射了。

到此这篇关于如何使用graalvm为带有反射功能的java代码生成native image的文章就介绍到这了,更多相关graalvm 生成native image内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 最新jsonwebtoken-jwt 0.12.3 基本使用小结

    最新jsonwebtoken-jwt 0.12.3 基本使用小结

    这篇文章主要介绍了最新jsonwebtoken-jwt 0.12.3 基本使用小结,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-12-12
  • Java中的Apache Commons Math使用详解

    Java中的Apache Commons Math使用详解

    Java中的Apache Commons Math是一个开源的数学库,它提供了许多常用的数学函数和算法,这个库对于需要处理大量数据的开发者来说非常有用,因为它可以大大简化代码并提高效率,本文给大家详解讲解Java中的Apache Commons Math知识,感兴趣的朋友跟随小编一起看看吧
    2023-08-08
  • Proxy实现AOP切面编程案例

    Proxy实现AOP切面编程案例

    这篇文章主要介绍了Proxy实现AOP切面编程案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • java实现身份证号码验证的示例代码

    java实现身份证号码验证的示例代码

    这篇文章主要为大家详细介绍了如何利用java语言实现身份证号码验证的功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-09-09
  • Java多线程中wait、notify、notifyAll使用详解

    Java多线程中wait、notify、notifyAll使用详解

    这篇文章主要介绍了Java多线程中wait、notify、notifyAll使用详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-05-05
  • java求数组元素重复次数和java字符串比较大小示例

    java求数组元素重复次数和java字符串比较大小示例

    这篇文章主要介绍了java求数组元素重复次数和java字符串比较大小示例,需要的朋友可以参考下
    2014-04-04
  • mybatis之BaseTypeHandler用法解读

    mybatis之BaseTypeHandler用法解读

    这篇文章主要介绍了mybatis之BaseTypeHandler用法解读,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • Java模拟多线程实现抢票代码实例

    Java模拟多线程实现抢票代码实例

    这篇文章主要介绍了Java模拟多线程实现抢票,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • Spring通过Java配置集成Tomcat的方法

    Spring通过Java配置集成Tomcat的方法

    这篇文章主要介绍了Spring通过Java配置集成Tomcat的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • 深度解析Spring Filter方法示例

    深度解析Spring Filter方法示例

    这篇文章主要为大家介绍了深度解析Spring Filter用法示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08

最新评论