使用graalvm為帶有反射功能的java代碼生成native?image的示例詳解
譯自Configure Native Image with the Tracing Agent graal官方文檔 , 以下所有命令需要在linux環(huán)境下操作,graalvm也支持windows。
要為使用 Java 反射、動態(tài)代理對象、JNI 或類路徑資源的 Java 應用程序構建本機可執(zhí)行文件,應為 native-image 工具提供 JSON 格式的配置文件或在代碼中預先計算元數(shù)據(jù)。
您可以手動創(chuàng)建配置文件,但更方便的方法是使用跟蹤代理(即Tracing agent,下面用代理一詞代稱)生成配置。本指南演示如何使用代理進行配置 native-image 。當您在 JVM 上運行應用程序時,代理會自動為您生成配置。
若要了解如何使用代碼中預先計算的元數(shù)據(jù)生成本機可執(zhí)行文件,請參閱文檔 - Reachability Metadata 可訪問性元數(shù)據(jù)。
本指南中的示例應用程序使用 Java 反射。該 native-image 工具僅部分檢測使用 Java 反射 API 訪問的應用程序元素。因此,您需要向它提供有關反射訪問的類、方法和字段的詳細信息。
不配置Json格式的反射信息示例
- 確保您已安裝 GraalVM JDK,下載地址如下:https://www.oracle.com/java/technologies/downloads/ 選擇graalvm的版本即可
將以下源代碼保存在名為 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 應用程序使用命令行參數(shù)來確定要執(zhí)行的反射操作。
運行如下命令:
$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 命令創(chuàng)建本機可執(zhí)行文件,如下所示:
$JAVA_HOME/bin/native-image --no-fallback ReflectionExample
使用以下命令運行生成的本機可執(zhí)行文件:
./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)
這表明,根據(jù)靜態(tài)分析,native-image 工具無法確定 StringReverser 類是否被使用,所以未將其包含在本機可執(zhí)行文件中。
配置Json格式的反射信息示例
以下步驟演示如何使用代理及其輸出來創(chuàng)建依賴于反射且需要配置的本機可執(zhí)行文件。
在工作目錄中創(chuàng)建名為 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"
此命令創(chuàng)建一個名為 reflect-config.json 的文件,其中包含類 StringReverser 的名稱及其 reverse() 方法。
[ { "name":"StringReverser", "methods":[{"name":"reverse","parameterTypes":["java.lang.String"] }] } ]
構建本機可執(zhí)行文件:
$JAVA_HOME/bin/native-image ReflectionExample
native-image 工具會自動使用 META-INF/native-image 目錄中的配置文件。但是,建議將 META-INF/native-image 目錄放到類路徑上,可以通過 JAR 文件或使用標志 -cp 。(這樣可以避免 IDE 用戶在目錄結構由 IDE 本身定義時出現(xiàn)混淆。)
測試可執(zhí)行文件
./reflectionexample StringReverser reverse "hello" # 輸出 olleh
./reflectionexample StringCapitalizer capitalize "hello"
執(zhí)行后會看到一個異常,類似于:
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 文件或重新運行跟蹤代理以更新現(xiàn)有配置文件,如下所示:
$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"] }] } ]
重新生成本機可執(zhí)行文件并運行,不會有報錯了。
$JAVA_HOME/bin/native-image ReflectionExample
./reflectionexample StringCapitalizer capitalize "hello"
總結
graalvm讓native鏡像支持反射的關鍵是利用json提前告訴它哪些類的哪些方法會被反射調(diào)用,然后它就能力在運行時支持反射了。
到此這篇關于如何使用graalvm為帶有反射功能的java代碼生成native image的文章就介紹到這了,更多相關graalvm 生成native image內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
基于java中byte數(shù)組與int類型的轉換(兩種方法)
下面小編就為大家?guī)硪黄趈ava中byte數(shù)組與int類型的轉換(兩種方法)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-08-08java 讀寫Parquet格式的數(shù)據(jù)的示例代碼
本篇文章主要介紹了java 讀寫Parquet格式的數(shù)據(jù)的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-09-09sharding-jdbc實現(xiàn)分頁查詢的示例代碼
sharding-jdbc是一個輕量級Java框架,它提供了分布式數(shù)據(jù)庫中間件的功能,支持水平分表和分庫分表,在分頁查詢方面,sharding-jdbc支持兩種方式:基于物理分頁和基于邏輯分頁,本文給大家介紹sharding-jdbc如何實現(xiàn)分頁查詢,需要的朋友可以參考下2024-05-05Java下載遠程服務器文件到本地(基于http協(xié)議和ssh2協(xié)議)
這篇文章主要介紹了Java下載遠程服務器文件到本地的方法(基于http協(xié)議和ssh2協(xié)議),幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2021-01-01