ノート:
- このチュートリアルは、Oracle提供の無料ラボ環境で入手できます。
- Oracle Cloud Infrastructureの資格証明、テナンシおよびコンパートメントに例の値を使用します。演習を完了するときは、これらの値をクラウド環境に固有の値に置き換えます。
GraalVM Native Imageのスタート・ガイド
イントロダクション
このラボでは、GraalVM Native Imageを使用して、クラウド・ネイティブJavaアプリケーションを構築するプロセスを段階的に説明します。Javaの知識を持つ開発者を対象としています。
GraalVM Native Image技術では、Javaコードを時間を前もって自己完結型の実行可能ファイルにコンパイルします。実行時にアプリケーションで必要とされるコードのみが、実行可能ファイルに追加されます。
ネイティブ・イメージによって生成される実行可能ファイルには、次のような重要な利点があります。
- JVMに必要なリソースの一部を使用するため、実行速度が低い
- ミリ秒単位で開始
- ウォームアップなく、ピーク・パフォーマンスをすぐに実現
- 軽量コンテナ・イメージにパッケージ化することで、より迅速かつ効率的なデプロイメントを実現できます。
- 攻撃対象領域を削減します(今後のラボではさらに活用)。
業界をリードするマイクロサービス・フレームワークの多くは、Micronaut、Spring、Helidon、Quarkusなど、GraalVM Native Imageのコンパイルを事前にサポートしています。
また、ネイティブ・イメージ用のMavenおよびGradleプラグインがあるため、Javaアプリケーションを実行可能ファイルとして簡単に構築、テストおよび実行することができます。
注意: Oracle Cloud Infrastructure (OCI)は、追加コストなしでGraalVM Enterpriseを提供します。
推定ラボ時間: 45分
ラボの目的
この演習では、次のタスクを実行します。
- Oracle Cloudのリモート・ホストに接続- Oracle Cloudコンピュート・ホストでアプリケーションを開発します
- GraalVMを使用してJavaアプリケーションを構築および実行
- GraalVM Native Imageを使用したJavaアプリケーションの実行可能ファイルへの変換
- Javaの動的機能と連携する実行可能ファイルの作成
- Maven GraalVMプラグインを使用したGraalVMネイティブ・イメージでの実行可能ファイルのビルド
注:ラボにラップトップアイコンが表示されている場合は、コマンドの入力などを実行する必要があります。その事に注意しなさい。
# This is where we you will need to do something
ステップ1:リモート・ホストへの接続および開発環境の確認
開発環境は、リモート・ホスト(Oracle Linux 8、1 CPUおよび32GBのメモリーを備えたOCIコンピュート・インスタンス)によって提供されます。
Luna Labsデスクトップ環境は、リモート・ホストの準備が完了する前に表示され、最大2分かかる場合があります。
リモート・ホストへの接続は、Lunaデスクトップ環境でセットアップ・スクリプトを実行します。このスクリプトは、「リソース」タブで使用できます
-
デスクトップで、「Luna-Lab.html」アイコンをダブルクリックします。ページが開き、ラボに固有のOracle Cloud Infrastructure資格証明および情報が表示されます。
-
「リソース」タブが表示されます。コンピュート・インスタンスが10分のクラウドでプロビジョニングされている間は、「リソース」タイトルの横に表示された歯車が回転することに注意してください。
-
インスタンスのプロビジョニング時に最大2分かかる場合、「リソース」タブに次が表示されます
-
「リソース」タブから、VSコード環境を設定する構成スクリプトをコピーします。「詳細の表示」リンクをクリックして、構成を表示します。次のスクリーンショットに示すように、これをコピーします。
-
次のスクリーンショットに示すように、ターミナルを開きます。
-
構成コードを端末に貼り付け、VSコードを開きます。
完了しました。これで、Oracle Cloudのリモート・ホストに正常に接続されました。
開発環境でのノート
このラボでは、JavaプラットフォームとしてGraalVM Enterprise 21を使用します。GraalVMは、信頼性が高く安全なOracle Java SE上に構築された、Oracleからの高パフォーマンスのJDKディストリビューションです。
この演習に必要なGraalVMとネイティブ・イメージ・ツールがあらかじめ構成されています。
端末で次のコマンドを実行すると、簡単に確認できます。VSコードTerminal > New Terminal
内から端末を作成できます。
java -version
native-image --version
ステップ2:デモ・アプリケーションのビルドと実行
デモ・アプリケーションを使用して、GraalVM Native Imageを紹介します。これは、現在のディレクトリとそのサブディレクトリに含まれるファイルの数をカウントするコマンドラインJavaアプリケーションです。さらに、アプリケーションはファイルの合計サイズも計算します。
アプリケーションのソースコードは、リモートホストで使用できます。
デモ・アプリケーションのノート
アプリケーションは、src
ディレクトリにある2つのJavaファイルで構成されます。
App.java
:ListDir
クラスのラッパー。ListDir.java
:すべての作業を実行します。ファイルがカウントされ、出力がまとめられます。
アプリケーションは、手作業で構築することも、Mavenプロファイルを使用して構築することもできます。Mavenビルド構成は、pom.xml
ファイルで提供されます。Mavenプロファイルは、1つのpom.xml
ファイル内に異なるビルド構成を持つ優れた方法です。Mavenプロファイルの詳細は、ここで確認できます。
開いているVSコード内のファイルを参照できます。
この演習では、いくつかのプロファイルを使用します。各プロファイルには特定の目的があります。
native
:このプロファイルは、GraalVM Native Imageを使用して実行可能ファイルを作成します。java_agent
:このプロファイルは、アプリケーション内の動的コードのすべての使用状況を追跡し、この情報を構成ファイルに取得するトレース・エージェントを使用してJavaアプリケーションを作成します。詳細については後述します。
特定のMavenプロファイルは、パラメータとしてmvn
コマンドに渡すことによって使用します。プロファイルの名前は、-P
フラグに追加されます。VSコード内のターミナル内から次のコマンドを実行できます。
次の例は、Mavenを使用して構築するときにnative
プロファイルをコールする方法を示しています:
mvn clean package -Pnative
これで、アプリケーションの動作を基本的に理解して、その動作を確認します。
-
プロジェクトを構築し、VS Codeで開かれたターミナル内から実行します。
mvn clean package exec:exec
前述のコマンドは次のとおりです:
- 生成されたアーティファクトまたはコンパイル済のアーティファクトを削除するには、プロジェクトをクリアします。
- アプリケーションを含む実行可能なJARファイルを作成します。このJARファイルは、後でネイティブ・イメージで使用されます。
exec
プラグインを実行してアプリケーションを実行します。
生成された出力には次のものが表示されます(アプリケーションによって報告されるファイルの数は異なる場合があります)。
Counting directory: . Total: 15 files, total size = 511.9 KiB [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------
ステップ3:実行可能ファイルへのJavaアプリケーションの変更
次に、GraalVM Native Imageを使用して、アプリケーションの実行可能バージョンを作成します。簡潔なリマインダとして、GraalVM Native Imageは、Javaアプリケーションを、JDKの実行を必要としない自己完結型の実行ファイルに変換する、すぐに開始して効率化できるコンパイル・テクノロジです。
GraalVM Native Imageは、リモート・ホストに事前インストールされています。
-
最初に、
target
ディレクトリにコンパイル済JARファイルがあることを確認します。ls ./target drwxrwxr-x 1 krf krf 4096 Mar 4 11:12 archive-tmp drwxrwxr-x 1 krf krf 4096 Mar 4 11:12 classes drwxrwxr-x 1 krf krf 4096 Mar 4 11:12 generated-sources -rw-rw-r-- 1 krf krf 496273 Mar 4 11:38 graalvmnidemos-1.0-SNAPSHOT-jar-with-dependencies.jar -rw-rw-r-- 1 krf krf 7894 Mar 4 11:38 graalvmnidemos-1.0-SNAPSHOT.jar drwxrwxr-x 1 krf krf 4096 Mar 4 11:12 maven-archiver drwxrwxr-x 1 krf krf 4096 Mar 4 11:12 maven-status
必要なファイルは
graalvmnidemos-1.0-SNAPSHOT-jar-with-dependencies.jar
です。 -
コマンドラインから実行可能ファイルを生成します。Mavenプラグインを使用してGraalVM Native Imageを使用する必要はありませんが、これは役立ちます。プロジェクトのルート・ディレクトリ
demo
から次を実行します。native-image -jar ./target/graalvmnidemos-1.0-SNAPSHOT-jar-with-dependencies.jar --no-fallback -H:Class=oracle.App -H:Name=file-count
これにより、現在のディレクトリ内に
file-count
という実行可能ファイルが生成されます。 -
この実行可能ファイルを次のように実行します。
./file-count
-
アプリケーションを実行する時刻。最初に実行可能ファイルとして実行し、次に通常の
java
コマンドを使用します。time ./file-count
time java -cp ./target/graalvmnidemos-1.0-SNAPSHOT-jar-with-dependencies.jar oracle.App
native-image
コマンドによって生成された実行可能ファイルは、対応するJavaアプリケーションよりも大幅に高速で実行されます。
実行可能ファイルの作成方法を少し詳しく説明します。
ステップ2でnative-image
コマンドに渡したパラメータは何を指定しますか。
-jar
: Javaアプリケーションを含むJARファイルの場所を指定します。(-cp
を使用してクラスパスを指定することもできます。)--no-fallback
:フォールバック・イメージを生成しません。(フォールバック・イメージを実行するにはJVMが必要であり、これは必要ありません。)-H:Class
:エントリ・ポイント・メソッド(main
メソッド)を提供するクラスを指定します。-H:Name
:出力実行可能ファイルの名前を指定します。
完全なドキュメントはここにあります。
GraalVM Native Image Mavenプラグインを使用して、native-image
ツールを実行することもできます。プロジェクトpom.xml
(Maven構成)ファイルには、プラグインを使用して実行可能ファイルを構築する方法を示す次のスニペットが含まれています。
<!-- Native Image -->
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<version>${native.maven.plugin.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<id>build-native</id>
<goals>
<goal>build</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<skip>false</skip>
<imageName>${exe.file.name}</imageName>
<mainClass>${app.main.class}</mainClass>
<buildArgs>
<buildArg>--no-fallback</buildArg>
<buildArg>--report-unsupported-elements-at-runtime</buildArg>
</buildArgs>
</configuration>
</plugin>
ネイティブ・イメージMavenプラグインは、実行可能ファイルを作成する重いリフトを実行します。<skip>true</skip>
タグを使用して無効にできます。また、<buildArgs/>
タグを介してパラメータをnative-image
に渡すこともできます。
GraalVM Native Imageプラグインについては、こちらをご覧ください。
Mavenプロファイルを使用して実行可能ファイルをビルドするには、次を実行します:
mvn clean package -Pnative
Mavenビルドによって、実行可能ファイルfile-count
がtarget
ディレクトリに配置されます。
実行可能ファイルは、次のように実行できます。
./target/file-count
ステップ4:リフレクションの使用- Log4Jへの依存性の追加
このステップでは、Javaの動的機能と連携する実行可能ファイルを構築します。
リフレクションに依存するアプリケーションにライブラリまたはコードを追加するとします。リフレクションをテストする適切な候補は、Log4Jロギング・フレームワークです。プロジェクトpom.xml
ファイルの依存性としてすでに追加されています。
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
log4j
を使用するようにアプリケーションを変更するには、ListDir.java
ファイルを編集し、いくつかの行をコメント解除します。
-
VSコードを使用して、
ListDir.java
ファイルを開きます -
log4j
インポートを宣言する行のコメントを解除し、次の行のコメントを解除します。//import org.apache.log4j.Logger;
//final static Logger logger = Logger.getLogger(ListDir.class);
/* // Add some logging if(logger.isDebugEnabled()){ logger.debug("Processing : " + dirName); } */
/* // Add some logging if(logger.isDebugEnabled()){ logger.debug("Processing : " + f.getAbsolutePath()); } */
-
ファイルを保存します
アプリケーションにロギングを追加したので、再構築して実行することにより、変更の結果を表示できます。
mvn clean package exec:exec
前の手順と同じ種類の出力が表示されますが、さらにロギングが追加されています。
-
次に、Mavenプロファイルを使用して実行可能ファイルを作成します。
mvn clean package -Pnative
-
作成した実行可能ファイルを実行します。これには、ロギングが含まれます。
./target/file-count
これにより、次のエラーが生成されます。
Exception in thread "main" java.lang.NoClassDefFoundError at org.apache.log4j.Category.class$(Category.java:118) at org.apache.log4j.Category.<clinit>(Category.java:118) at java.lang.Class.ensureInitialized(DynamicHub.java:552) at oracle.ListDir.<clinit>(ListDir.java:75) at oracle.App.main(App.java:63) Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Category at java.lang.Class.forName(DynamicHub.java:1433) at java.lang.Class.forName(DynamicHub.java:1408) ... 5 more
ここで何が起こったのですか。
Javaの動的機能の操作
この例外は、リフレクションに依存するため、Log4Jライブラリの追加によって発生します。native-image
ツールは、積極的な静的分析を実行して、アプリケーション内でどのクラスが使用されているかを確認します。使用されていないクラスの場合、ツールはそれらが不要であると想定します。これは、「クローズされた世界」仮定と呼ばれます。ロードする必要があるものは、実行可能ファイルの作成時に知っておく必要があります。静的分析で検索できない場合、実行可能ファイルには含まれません。
反射はJavaのコア機能なので、反射は使用し、GraalVM Native Imageで提供されるスピードアップをどのように利用できますか。リフレクションの使用についてnative-image
ツールに知らせる方法が必要です。
native-image
ツールは、リフレクションを介して参照されるすべてのクラスを指定する構成ファイルで読み取ることができます。
これは手動で実行することも、GraalVM Javaランタイムに付属のJavaトレース・エージェントでも実行できます。エージェントによってJSONファイルが生成され、リフレクション、JNI、プロキシおよびリソース・アクセスのすべてのインスタンスを記録し、アプリケーションの実行中に特定できます。
ノート:リフレクションのすべてのケースが確実に識別されるように、トレース・エージェントの実行時にアプリケーションのすべてのコード・パスを実行することが重要です。
トレース・エージェントの詳細なドキュメントはここにあります。
ステップ5:トレース・エージェントの使用
ここで、アプリケーションの実行中に、トレース・エージェントを使用してリフレクション構成を生成します。
-
トレース・エージェントを使用してアプリケーションを実行します。
java -agentlib:native-image-agent=config-output-dir=./src/main/resources/META-INF/native-image -cp ./target/graalvmnidemos-1.0-SNAPSHOT-jar-with-dependencies.jar oracle.App
トレース・エージェントが作成した構成ファイルを確認します。
ls -l src/main/resources/META-INF/native-image/
生成された出力には、次のものが表示されます。
total 56 -rw-r--r-- 1 kfoster staff 4B Dec 2 19:13 jni-config.json -rw-r--r-- 1 kfoster staff 86B Nov 9 20:46 native-image.properties -rw-r--r-- 1 kfoster staff 65B Dec 2 19:13 predefined-classes-config.json -rw-r--r-- 1 kfoster staff 4B Dec 2 19:13 proxy-config.json -rw-r--r-- 1 kfoster staff 521B Dec 2 19:13 reflect-config.json -rw-r--r-- 1 kfoster staff 101B Dec 2 19:13 resource-config.json -rw-r--r-- 1 kfoster staff 4B Dec 2 19:13 serialization-config.json
ノート:プロジェクトには、これを実行できるMavenプロファイルが含まれています。トレース・エージェントを使用するには、次のコマンドを実行します。
mvn clean package exec:exec -Pjava_agent
-
次に、実行可能ファイルを再度構築します。今回は、トレース・エージェントによって生成された構成ファイルが適用されます。
mvn package -Pnative
-
最後に、生成されたファイルを実行します。
time ./target/file-count
実行可能ファイルが機能し、予期したとおりに出力へのログ・メッセージが生成されます。
これは、トレース・エージェントによって生成されたファイルが、リフレクションによって参照されるクラスを記録しているために機能します。native-image
ツールでは、アプリケーション内で使用されているため、生成された実行可能ファイルから除外されないことが認識されるようになりました。
-agentlib
パラメータの位置に注意してください
エージェント・パラメータは、-jar
または-classpath
パラメータの前になる必要があります。また、ファイルを書き込むディレクトリも指定する必要があります。推奨される場所はsrc/main/resources/META-INF/native-image
にあります。この場所に配置されたファイルは、native-image
ツールによって自動的に取得されます。
実行可能ファイルの生成の構成に関するノート
Javaプロパティ・ファイル(デフォルトではsrc/main/resources/META-INF/native-image/native-image.properties
)を使用して、native-image
ツールにパラメータを渡すこともできます。demo
ディレクトリにサンプル・ファイルがあり、これを使用して実行できることを把握できます。
結論
このラボでは、GraalVM Native Imageのいくつかの機能を試してみました。
- Javaコマンドライン・アプリケーションから高速実行可能ファイルを生成する方法
- Mavenを使用して実行可能ファイルを構築する方法
- トレースエージェントを使用してリフレクションを追跡および記録するプロセスを自動化する方法
GraalVM Native Imageを使用した効率的で安全かつ即時利用可能なクラウド・ネイティブJavaアプリケーションの記述
さらに学ぶ
- ネイティブ・イメージ・アーキテクトであるChristian Wimmer GraalVM Native Image: Javaの大規模な静的分析によるプレゼンテーションをご覧ください
- GraalVM Native Imageのリファレンス・ドキュメント
その他の学習リソース
docs.oracle.com/learnの他のラボを調べるか、Oracle Learning YouTubeチャネルでさらに無料の学習コンテンツにアクセスします。さらに、education.oracle.com/learning-explorerにアクセスしてOracle Learning Explorerにします。
製品ドキュメントは、Oracleヘルプ・センターを参照してください。
GraalVM Native Image Quick Start
F51540-04
March 2022
Copyright © 2022, Oracle and/or its affiliates.