首页 > 编程语言 >如何使用graalvm为带有反射功能的java代码生成native image

如何使用graalvm为带有反射功能的java代码生成native image

时间:2024-02-08 17:22:23浏览次数:31  
标签:代码生成 java String image ReflectionExample StringReverser native

译自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格式的反射信息示例

  1. 确保您已安装 GraalVM JDK,下载地址如下:https://www.oracle.com/java/technologies/downloads/ 选择graalvm的版本即可
  2. 将以下源代码保存在名为 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 应用程序使用命令行参数来确定要执行的反射操作。
  3. 运行如下命令:
    $JAVA_HOME/bin/javac ReflectionExample.java   # 编译
    $JAVA_HOME/bin/java ReflectionExample StringReverser reverse "hello"   # 输出 olleh
    $JAVA_HOME/bin/java ReflectionExample StringCapitalizer capitalize "hello"   # 输出 HELLO
    
  4. 使用 native-image 命令创建本机可执行文件,如下所示:
     $JAVA_HOME/bin/native-image --no-fallback ReflectionExample
    
  5. 使用以下命令运行生成的本机可执行文件:
    ./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格式的反射信息示例

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

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

    mkdir -p META-INF/native-image
    
  2. 在启用代理的情况下运行应用程序生成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"] }]
     }
    ]
    
  3. 构建本机可执行文件:

    $JAVA_HOME/bin/native-image ReflectionExample
    

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

  4. 测试可执行文件

    ./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 的引用。

  5. 更新配置以包含类 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"] }]
         }
     ]
    
    
  6. 重新生成本机可执行文件并运行,不会有报错了。

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

总结

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

标签:代码生成,java,String,image,ReflectionExample,StringReverser,native
From: https://www.cnblogs.com/vant/p/18011963

相关文章

  • java11下载安装
    https://www.oracle.com/in/java/technologies/javase/jdk11-archive-downloads.html https://jdk.java.net/java-se-ri/11-MR2 ......
  • java的SPI机制
    参考https://blog.csdn.net/qq_52423918/article/details/1309683071概念JavaSPI(ServiceProviderInterface)是Java官方提供的一种服务发现机制,它允许在运行时动态地加载实现特定接口的类,而不需要在代码中显式地指定该类,从而实现解耦和灵活性。2实现原理JavaSPI的实现原......
  • Java中的审批流:BPMN与Flowable
    最近闲来无事,研究了一下工作流框架。找到了一条可以实现审批流程的技术方向。我选择的后端工作流框架是Flowable,看文档应该是属于Activity的一个分支吧。使用教程文档地址在:GettingStarted·FlowableOpenSourceDocumentation(用百度/必应搜索,搜到的是Flowable的官网,最后这个......
  • Java反射(learning)
    Java-reflectionJava反射(Reflection)是Java语言的一个特性,它允许程序在运行时检查和修改内部类的行为。通过反射,可以获取类的构造器、方法、字段等成员的信息,并且可以动态地创建对象、调用方法、访问和修改字段。Java反射主要涉及到以下几个类:java.lang.Class:代表一个类,每个......
  • 解析Sermant热插拔能力:服务运行时动态挂载JavaAgent和插件
    本文分享自华为云社区《服务运行时动态挂载JavaAgent和插件——Sermant热插拔能力解析》,作者:华为云高级软件工程师栾文飞一、概述Sermant是基于Java字节码增强技术的无代理服务网格,其利用Java字节码增强技术,为宿主应用程序提供服务治理功能,以解决大规模微服务场景中的服务治理......
  • el-image实现在el-table-column中展示多张图片,且能够大图循环预览
    效果:能在表格中展示且点击需要查看的即可放大查看,多组图片放大时可左右切换  核心代码:注意:workPhoto是图片地址的数组通过v-for来遍历每个列表的图片地址数组,结合:src="item"把每个图片展示在表格里,展示图片的大小样式用style来设定通过:perview-src-list="getImgList(s......
  • 深入理解 Java 循环结构:while、do while、for 和 for-each 循环
    Java循环循环可以执行一个代码块,只要达到指定的条件。循环很方便,因为它们节省时间,减少错误,并使代码更易读。JavaWhile循环while循环会循环执行一个代码块,只要指定的条件为真:语法while(condition){//要执行的代码块}在下面的示例中,只要变量(i)小于5,循环中的代码将......
  • Java 中的Collections工具类
    Collections工具类java.util.Collection集合接口java.util.Collections集合工具类,方便集合操作对List集合中元素排序,需要保证List集合中元素实现了Comparable接口Collections.synchronizedList(list);设置成线程安全的Collections.sort(wuGuis);进行排序importjava......
  • javascript 下载 application/octet-stream 文件
    functiondownloadFile(id){varxhr=newXMLHttpRequest();xhr.open('POST','https://localhost/api/app/isp-detection/'+id+'/download');xhr.responseType='blob';xhr.setRequestHeader('Cont......
  • 编程新手必学:Java运算符详解
    编程新手必学:Java运算符详解编程,这种强大的艺术形式,给我们带来了无穷的可能性。就像数学中的加减乘除,程序设计中也有一种类似的工具:运算符。作为一种编程语言,Java提供了一系列的运算符来执行各种基础和复杂的操作。在本文中,我将尝试解释Java中的各种运算符,并提供一些代码示例来说......