即時編譯支援

目錄

簡介

Tomcat 支援使用 GraalVM/Mandrel 原生映像工具來產生包含容器的原生二進位檔。此文件頁面說明此類映像的建置流程。

設定

原生映像工具比較容易用於單一 JAR,因此此流程將使用 Maven shade 外掛 JAR 封裝。其構想是產生一個單一 JAR,其中包含 Tomcat、Web 應用程式和所有其他相依性的所有必要類別。雖然 Tomcat 已收到相容性修正程式以支援原生映像,但其他函式庫可能不相容,可能需要替換程式碼(GraalVM 文件有更詳細的說明)。

下載並安裝 GraalVM 或 Mandrel。

https://github.com/apache/tomcat/tree/10.1.x/modules/stuffed 下載 Tomcat Stuffed 模組。為方便起見,可以設定環境屬性

export TOMCAT_STUFFED=/absolute...path...to/stuffed
建置程序現在需要 Apache Ant 和 Maven。

封裝和建置

$TOMCAT_STUFFED 資料夾內,目錄結構與一般 Tomcat 相同。主要設定檔放置在 conf 資料夾中,如果使用預設的 server.xml,則 Web 應用程式會放置在 webapps 資料夾中。

所有 Web 應用程式類別都必須提供給 Maven shade 外掛程式,以及在 JSP 預編譯步驟中的編譯器。存在於 /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
現在應將 Web 應用程式的相依性新增到主 $TOMCAT_STUFFED/pom.xml,然後建置 shade 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
然後停止 Tomcat 並使用下列指令包含產生的嵌入式程式碼
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 應用程式中所有導致動態類別載入的路徑(例如:Servlet 存取、WebSocket 等),該腳本會執行 Web 應用程式。Servlet 可以在啟動時載入,而不需要實際存取。偵聽器也可以用於在啟動時載入其他類別。完成後,可以停止 Tomcat。

描述符現在已在代理輸出目錄中產生。此時,必須進行進一步的設定,以新增未追蹤的項目,包括:基本介面、資源組合、基於 BeanInfo 的反射等。有關此程序的更多資訊,請參閱 Graal 文件。

即使必須將所有使用的類別 AOT 編譯到原生映像中,Web 應用程式仍必須保持不變,並繼續在 WEB-INF 資料夾中包含所有必要的類別和 JAR。儘管這些類別實際上不會執行或載入,但需要存取它們。

建置原生映像

如果一切順利,現在可以使用 native-image 工具建置原生映像。

$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

相容性

在原生映像中,預設支援 Servlet、JSP、EL、Websocket、Tomcat 容器、tomcat-native、HTTP/2。

在撰寫此文件時,由於 Graal 不支援記錄管理員設定屬性,且有一些靜態初始化問題,因此不支援 JULI,而應改用一般的 java.util.logging 記錄器和實作。

如果使用預設的 server.xml 檔案,必須從設定中移除一些伺服器監聽器,因為它們與原生映像不相容,例如 JMX 監聽器(不支援 JMX)和防護外洩監聽器(使用 Graal 中不存在的內部程式碼)。

缺少項目以改善 Tomcat 功能

  • java.util.logging LogManager:尚未實作透過系統屬性的設定,因此必須使用標準 java.util.logging,而不能使用 JULI
  • 靜態連結設定:tomcat-native 無法靜態連結