使用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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java实现计算周期性提醒的示例

    java实现计算周期性提醒的示例

    本文分享一个java实现计算周期性提醒的示例,可以计算父亲节、母亲节这样的节日,也可以定义如每月最好一个周五,以方便安排会议
    2014-04-04
  • 命令行中 javac、java、javap 的使用小结

    命令行中 javac、java、javap 的使用小结

    使用 java 命令运行一个.class文件,需要使用该类的全限定类名,同时需要在当前路径下有该类的包层次文件夹,这篇文章主要介绍了命令行中 javac、java、javap 的使用小结,需要的朋友可以参考下
    2023-07-07
  • 使用Maven中的scope总结

    使用Maven中的scope总结

    这篇文章主要介绍了使用Maven中的scope总结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • Java通过freemarker生成Word文档导出的方式详解

    Java通过freemarker生成Word文档导出的方式详解

    本文详细介绍了如何使用FreeMarker模板生成Word文档,包括制作FTL模板、在Java中使用FreeMarker生成文档以及处理动态数据和合并单元格等内容,需要的朋友可以参考下
    2025-03-03
  • SpringMvc响应数据及结果视图实现代码

    SpringMvc响应数据及结果视图实现代码

    这篇文章主要介绍了SpringMvc响应数据及结果视图实现代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • Java 将HTML转为XML的详细步骤

    Java 将HTML转为XML的详细步骤

    这篇文章主要介绍了Java 将HTML转为XML,本文将以html转为xml格式为例,介绍如何实现转换,以下是详细方法及步骤,需要的朋友可以参考下
    2022-06-06
  • java中 Map<String,Object>用法(示例代码整合)

    java中 Map<String,Object>用法(示例代码整合)

    Java中Map<String, Object>是参数化接口,用于存储键值对(键为String,值为Object),适用于动态数据存储、配置信息及JSON处理,需注意类型转换和空指针异常,下面通过示例代码给大家介绍java中 Map<String,Object>用法,感兴趣的朋友一起看看吧
    2025-07-07
  • 浅谈如何在项目中使用Spring Cloud Alibaba Sentinel组件

    浅谈如何在项目中使用Spring Cloud Alibaba Sentinel组件

    随着微服务的流行,服务和服务之间的稳定性变得越来越重要。本文主要介绍了使用Spring Cloud Alibaba Sentinel组件,感兴趣的可以了解一下
    2021-07-07
  • SpringBoot依赖及其作用分析

    SpringBoot依赖及其作用分析

    这篇文章主要介绍了SpringBoot依赖及其作用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • Java日常练习题,每天进步一点点(60)

    Java日常练习题,每天进步一点点(60)

    下面小编就为大家带来一篇Java基础的几道练习题(分享)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望可以帮到你
    2021-08-08

最新评论