BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース GraalVM 20.0: TomcatがWindowsのネイティブイメージとして実行可能に

GraalVM 20.0: TomcatがWindowsのネイティブイメージとして実行可能に

原文(投稿日:2020/03/15)へのリンク

JavaやPython、JavaSciptなど、複数言語で記述されたアプリケーション実行のための共有ランタイムを提供する多言語仮想マシンのGraalVMが、Windowsプラットフォームをフルサポートしたメジャーバージョン20.0をリリースした。GraalVM 20.0 Windowsディストリビューションには、JavaScriptエンジン、GraalVMアップデートユーティリティのgu、GraalVMコンパイラの使用可能なJDKが含まれている。LinuxやmacOS用のディストリビューションとは異なり、WindowsではまだNode.jsサポートが使用できない点には注意が必要だ。

GraalVMのネイティブイメージ生成ユーティリティもアップデートされて、Windows上で拡張サポートが提供されるようになった。ネイティブイメージは、事前(ahead-of-time)コンパイルされたJavaバイトコードをスタンドアロンの実行ファイルとしてパッケージしたもので、一般的に起動の高速化やフットプリントの縮小などのメリットがある。ネイティブイメージユーティリティは、GraalVMのアップデートユーティリティであるguを使ってインストールする。guは、GraalVMのコアディストリビューションに含まれないパッケージのダウンロードとインストールを目的としたパッケージマネージャである。

関連するニュースの中で、Apache Tomcat 9が、コンテナを含むGraalVMのネイティブイメージ生成をフルサポートするという発表があった。ただし、ネイティブイメージベースでTomcatを構築する場合には、TomcatのWebアプリが使用するサードパーティ製のライブラリがネイティブイメージをフルサポートしていない可能性がある点に注意しなければならない。例えば、あるライブラリが動的クラスローディングやリフレクションに依存している場合、ネイティブイメージの使用するコンフィギュレーションファイルを自動生成するために、最初にGraalVMベースのVMをトレーシングエージェントを使って実行しなければならない。生成されたファイルはWebアプリまたはjarのMETA-INF/native-image配下において、ネイティブイメージ内のリフレクションなどの機能をサポートするために使用する。

以下のコード例は、組み込みTomcatサーバを実行するシンプルなJava 11クラスである。

public class TED {

  public static void main(String... args)
      throws Exception {
    File baseFolder = new File(System.getProperty("user.dir"));
    File appsFolder = new File(baseFolder, "web-apps");

    var tomcat = new Tomcat();
    tomcat.setBaseDir(baseFolder.getAbsolutePath());
    tomcat.setPort(8080);
    tomcat.getHost().setAppBase(appsFolder.getAbsolutePath());

    // Call the connector to create the default connector.
    tomcat.getConnector();

    tomcat.getHost().setAppBase(appsFolder.getAbsolutePath());
    var wrapper = tomcat.addServlet("", "hello", new HelloServlet());
    wrapper.setLoadOnStartup(1);
    wrapper.addMapping("/*");

    tomcat.start();
    tomcat.getServer().await();
  }

  private static class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws IOException {
      resp.setStatus(200);

      var writer = resp.getWriter();
      writer.write("Hello from Tomcat native image!");
      writer.flush();
      writer.close();
    }
  }
}

native-imageユーティリティでは単一JARファイルの方が扱いやすいので、Maven ShadeプラグインGradle Shadowプラグインを使って、クラスをuber JAR(実行可能なJARファイル)にコンパイルおよびビルドしておくとよいだろう。uber JARが完成すれば、GraalVMトレーシングエージェントを実行して、ネイティブイメージ用のコンフィギュレーションファイルを生成すればよい。以下のスニペットは、GraalVMトレーシングツールを使ってリフレクション、JNI(Java Native Service)、クラスパスリソース、動的プロキシ用のコンフィギュレーションファイルを生成する方法を示したものだ。

java \
  -agentlib:native-image-agent=config-merge-dir=graal-conf \
  -cp build/libs/ted-1.0-all.jar my.example.TED

トレーシングアージェントは、native-imageユーティリティの入力となる、さまざまなコンフィギュレーションファイルをJSON形式で生成してくれる。

native-image --no-server \
  -cp build/libs/ted-0.0.1-SNAPSHOT-all.jar \
  --allow-incomplete-classpath \
  -H:+JNI -H:+ReportUnsupportedElementsAtRuntime \
  -H:+ReportExceptionStackTraces -H:EnableURLProtocols=http,jar,jrt \
  -H:ConfigurationFileDirectories=graal-conf/ \
  -H:ReflectionConfigurationFiles=graal-conf/reflect-config.json \
  -H:ResourceConfigurationFiles=graal-conf/resource-config.json \
  -H:JNIConfigurationFiles=graal-conf/jni-config.json \
  my.example.TED ted

上の例では、ユーティリティが40MB程度のファイルとしてtedというネイティブバイナリを生成する。このファイルはJDKやJREなしで実行が可能である。

./ted

http://localhost:8006にナビゲートされ、例に挙げたJavaクラスで定義したようなハローメッセージが表示されるはずだ。

Hello from Tomcat native image!

Javaシリアライゼーション、JMX、JULItomcat-nativeの静的リンクなど、Tomcatのいくつかの機能は、GraalVMネイティブイメージ内ではまだサポートされていないため、注意が必要だ。

ネイティブイメージの改善とWindowsサポートに加えて、GraalVMのWebAssembly言語実装であるGraalWasmが、試験的機能として利用可能になった。多言語APIを使用すれば、webassemblyバイナリをJavaアプリケーションに組み込んで実行することができる。

GraalVMのJavaに関して、もうひとつ注目に値する変更は、ThreadPriorityPolicyのデフォルト設定が1になったことだ。これにより、Java内で設定されたスレッドのプライオリティが、OSのネイティブスレッドのプライオリティに反映されるようになる。ThreadPriorityPolicyのデフォルト値はアプリケーションのパフォーマンスに影響する可能性があるため、パフォーマンスの重要なアプリケーションの移行時には注意する必要がある。

今回のリリースでは、ネイティブイメージ生成に関するJNIとJDK 11の問題のいくつかが解決されている。新しいJDK Flight Recordert Data Viewerが、VisualVMの拡張版であるGraalVM VisualVMに追加された。NodeJS、Ruby、LLVMのランタイムもアップグレードされている。GraalVM言語用Language Server Protocol実装のテクニカルプレビューがGraalVM VSCode Extensionで利用可能だ。

JDK 8およびJDK 11ベースのGraalVMディストリビューションは、いずれもGitHubからダウンロードすることができる。

この記事に星をつける

おすすめ度
スタイル

BT