事前コンパイルサポート
目次
はじめに
Tomcatは、GraalVM/Mandrelネイティブイメージツールを使用して、コンテナを含むネイティブバイナリを生成することをサポートしています。このドキュメントページでは、そのようなイメージのビルドプロセスについて説明します。
セットアップ
ネイティブイメージツールは、単一のJARを使用する方がはるかに簡単です。そのため、このプロセスではMaven ShadeプラグインJARパッケージングを使用します。これは、Tomcat、Webアプリケーション、およびすべての追加の依存関係から必要なすべてのクラスを含む単一のJARを作成するというアイデアです。Tomcatはネイティブイメージをサポートするための互換性修正を受けましたが、他のライブラリは互換性がない可能性があり、コードの置換が必要になる場合があります(GraalVMのドキュメントにはこれに関する詳細があります)。
GraalVMまたはMandrelをダウンロードしてインストールします。
https://github.com/apache/tomcat/tree/10.1.x/modules/stuffed
からTomcat Stuffedモジュールをダウンロードします。便宜上、環境プロパティを設定できます。
export TOMCAT_STUFFED=/absolute...path...to/stuffed
パッケージングとビルド
$TOMCAT_STUFFED
フォルダ内では、ディレクトリ構造は通常のTomcatと同じです。メインの設定ファイルはconf
フォルダに配置され、デフォルトのserver.xml
を使用する場合は、Webアプリケーションはwebapps
フォルダに配置されます。
すべてのWebアプリケーションクラスを、JSP事前コンパイルステップ中に、Maven Shadeプラグインとコンパイラで使用できるようにする必要があります。/WEB-INF/lib
にあるJARは、Maven依存関係として使用できるようにする必要があります。webapp-jspc.ant.xml
スクリプトは、Webアプリケーションの/WEB-INF/classes
フォルダから、Mavenがコンパイルターゲットとして使用するtarget/classes
パスにクラスをコピーしますが、JSPソースのいずれかがそれらを使用する場合は、代わりにJARとしてパッケージ化する必要があります。
最初のステップは、すべての依存関係を含むシェードされたTomcat JARをビルドすることです。Webアプリケーション内のJSPはすべて事前コンパイルしてパッケージ化する必要があります(webapps
に$WEBAPPNAME
Webアプリケーションが含まれていると仮定します)。
cd $TOMCAT_STUFFED
mvn package
ant -Dwebapp.name=$WEBAPPNAME -f webapp-jspc.ant.xml
$TOMCAT_STUFFED/pom.xml
に追加し、シェードされたJARをビルドします。mvn package
事前コンパイルでは、可能な限りリフレクションを使用しない方が良いので、メインのserver.xml設定とコンテキストの設定に使用されるcontext.xmlファイルから、Tomcat Embeddedコードを生成してコンパイルすることをお勧めします。
$JAVA_HOME/bin/java\
-Dcatalina.base=. -Djava.util.logging.config.file=conf/logging.properties\
-jar target/tomcat-stuffed-1.0.jar --catalina -generateCode src/main/java
mvn package
--catalina -useGeneratedCode
引数がコマンドラインに追加されていると仮定します。そうでない場合は、それらを除去する必要があります。
ネイティブイメージの設定
ネイティブイメージは、記述子に明示的に定義されていない限り、いかなる形式の動的クラスローディングやリフレクションもサポートしていません。それらを生成するには、GraalVMのトレーシングエージェントを使用し、場合によっては追加の手動設定が必要です。
GraalVMサブストレートVMとそのトレースエージェントを使用してTomcatを実行します。
$JAVA_HOME/bin/java\
-agentlib:native-image-agent=config-output-dir=$TOMCAT_STUFFED/target/\
-Dorg.graalvm.nativeimage.imagecode=agent\
-Dcatalina.base=. -Djava.util.logging.config.file=conf/logging.properties\
-jar target/tomcat-stuffed-1.0.jar --catalina -useGeneratedCode
これで、動的クラスローディングにつながるWebアプリケーションからのすべてのパス(例:サーブレットアクセス、WebSocketなど)に、Webアプリケーションを実行するスクリプトを使用してアクセスする必要があります。サーブレットは、実際のアクセスを必要とせずに起動時にロードされる場合があります。リスナーを使用して、起動時に追加のクラスをロードすることもできます。それが完了したら、Tomcatを停止できます。
記述子は、エージェントの出力ディレクトリに生成されました。この時点で、トレースされていないアイテムを追加するためのさらなる設定を行う必要があります。これには、基本インターフェース、リソースバンドル、BeanInfoベースのリフレクションなどが含まれます。このプロセスに関する詳細については、Graalのドキュメントを参照してください。
使用されるすべてのクラスをAOTでネイティブイメージにコンパイルする必要がある場合でも、Webアプリケーションは変更されたままにする必要があり、必要なすべてのクラスとJARをWEB-INF
フォルダに含め続ける必要があります。これらのクラスは実際には実行またはロードされませんが、それらへのアクセスが必要です。
ネイティブイメージのビルド
すべてが正しく実行された場合は、ネイティブイメージツールを使用してネイティブイメージをビルドできるようになりました。
$JAVA_HOME/bin/native-image --report-unsupported-elements-at-runtime\
--enable-http --enable-https --enable-url-protocols=http,https,jar,jrt\
--initialize-at-build-time=org.eclipse.jdt,org.apache.el.parser.SimpleNode,jakarta.servlet.jsp.JspFactory,org.apache.jasper.servlet.JasperInitializer,org.apache.jasper.runtime.JspFactoryImpl\
-H:+UnlockExperimentalVMOptions\
-H:+JNI -H:+ReportExceptionStackTraces\
-H:ConfigurationFileDirectories=$TOMCAT_STUFFED/target/\
-H:ReflectionConfigurationFiles=$TOMCAT_STUFFED/tomcat-reflection.json\
-H:ResourceConfigurationFiles=$TOMCAT_STUFFED/tomcat-resource.json\
-H:JNIConfigurationFiles=$TOMCAT_STUFFED/tomcat-jni.json\
-jar $TOMCAT_STUFFED/target/tomcat-stuffed-1.0.jar
--static
パラメーターにより、生成されたバイナリにglibc、zlib、およびlibstd++の静的リンクが可能になります。
ネイティブイメージの実行方法は次のとおりです。
./tomcat-stuffed-1.0 -Dcatalina.base=. -Djava.util.logging.config.file=conf/logging.properties --catalina -useGeneratedCode
互換性
サーブレット、JSP、EL、WebSocket、Tomcatコンテナ、tomcat-native、HTTP/2はすべて、ネイティブイメージでそのままサポートされています。
このドキュメントを作成時点では、ログマネージャー設定プロパティがGraalでサポートされていないこと、およびいくつかの静的イニシャライザーの問題があるため、JULIはサポートされていません。代わりに、通常のjava.util.loggingロガーと実装を使用する必要があります。
デフォルトのserver.xmlファイルを使用する場合、JMXリスナー(JMXはサポートされていません)やリーク防止リスナー(Graalに存在しない内部コードの使用)など、ネイティブイメージと互換性のない一部のサーバーリスナーを構成から削除する必要があります。
Tomcatの機能向上のための不足している項目
- java.util.logging LogManager:システムプロパティによる設定は実装されていないため、JULIの代わりに標準のjava.util.loggingを使用する必要があります。
- 静的リンク設定:tomcat-nativeは静的にリンクできません。