◀戻る
トレースエージェントを使用したネイティブイメージの設定
Javaリフレクション、動的プロキシオブジェクト、JNI、またはクラスパスリソースを使用するJavaアプリケーションのネイティブ実行ファイルをビルドするには、native-image
ツールにJSON形式のメタデータファイルを提供するか、コード内でメタデータを事前に計算する必要があります。
設定ファイルを手動で作成することもできますが、より便利な方法は、トレースエージェント(以降、エージェント)を使用して設定を生成することです。このガイドでは、エージェントを使用してnative-image
を設定する方法を示します。エージェントは、アプリケーションをJVMで実行するときに自動的に設定を生成します。
コード内で事前に計算されたメタデータを使用してネイティブ実行ファイルをビルドする方法については、ドキュメントを参照してください。
このガイドの例題アプリケーションでは、Javaリフレクションを使用しています。native-image
ツールは、Java Reflection APIを使用してアクセスされるアプリケーション要素を部分的にしか検出しません。そのため、リフレクションによってアクセスされるクラス、メソッド、フィールドに関する詳細情報を提供する必要があります。
設定なしの例
次のアプリケーションは、Javaリフレクションの使用を示しています。
前提条件
GraalVM JDKがインストールされていることを確認してください。SDKMAN!を使用すると簡単に開始できます。その他のインストールオプションについては、ダウンロードセクションをご覧ください。
- 次のソースコードを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アプリケーションは、コマンドライン引数を使用して実行する操作を決定します。
- 例をコンパイルし、以下の各コマンドを実行します。
javac ReflectionExample.java
java ReflectionExample StringReverser reverse "hello"
java ReflectionExample StringCapitalizer capitalize "hello"
各コマンドの出力は、それぞれ
"olleh"
と"HELLO"
である必要があります。(クラスまたはメソッドを識別するために他の文字列を提供すると、例外がスローされます。) - 次のようにネイティブ実行ファイルを作成します。
native-image --no-fallback ReflectionExample
注記:
native-image
の--no-fallback
オプションにより、実行ファイルを作成できない場合、ユーティリティは失敗します。 - 次のコマンドを使用して、生成されたネイティブ実行ファイルを実行します。
./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
がアプリケーションで使用されていることを特定できず、そのためネイティブ実行ファイルに含まれていなかったことを示しています。
設定を使用した例
次の手順では、エージェントとその出力を用いて、リフレクションに依存し、設定を必要とするネイティブ実行ファイルを作成する方法を示します。
- 作業ディレクトリにMETA-INF/native-image/という名前のディレクトリを作成します。
mkdir -p META-INF/native-image
- 次のように、エージェントを有効にしてアプリケーションを実行します。
java -agentlib:native-image-agent=config-output-dir=META-INF/native-image ReflectionExample StringReverser reverse "hello"
このコマンドは、クラス
StringReverser
とそのreverse()
メソッドの名前を含むrechability-metadata.jsonという名前のファイルを作成します。{ "reflection": [ { "type":"StringReverser", "methods":[{"name":"reverse","parameterTypes":["java.lang.String"] }] } ] }
- ネイティブ実行ファイルをビルドします。
native-image ReflectionExample
native-image
ツールは、META-INF/native-image/ディレクトリ内のメタデータファイルを自動的に使用します。ただし、JARファイル経由または-cp
オプションを使用して、META-INF/native-image/ディレクトリがクラスパス上にあることをお勧めします。(これにより、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
を含むように設定を更新します。reachability-metadata.jsonファイルを編集するか、config-merge-dir
オプションを使用して既存の設定ファイルを更新するためにトレースエージェントを再実行できます。次のとおりです。java -agentlib:native-image-agent=config-merge-dir=META-INF/native-image ReflectionExample StringCapitalizer capitalize "hello"
このコマンドは、クラス
StringCapitalizer
とそのcapitalize()
メソッドの名前を含むようにreachability-metadata.jsonファイルを更新します。{ "reflection": [ { "type":"StringCapitalizer", "methods":[{"name":"capitalize","parameterTypes":["java.lang.String"] }] }, { "type":"StringReverser", "methods":[{"name":"reverse","parameterTypes":["java.lang.String"] }] } ] }
- ネイティブ実行ファイルを再ビルドして実行します。
native-image ReflectionExample
./reflectionexample StringCapitalizer capitalize "hello"
アプリケーションはこれで意図したとおりに動作するはずです。