即时编译支持
目录
简介
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 模块。为方便起见,可以设置一个 env 属性
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。
第一步是用所有依赖项构建 shaded 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
中,然后构建 shaded 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
现在,需要使用一个脚本访问导致动态类加载(例如:Servlet 访问、websocket 等)的 Web 应用程序中的所有路径,该脚本将执行 Web 应用程序。Servlet 可以在启动时加载,而不需要实际访问。侦听器也可以用于在启动时加载其他类。完成后,可以停止 Tomcat。
描述符现已在代理输出目录中生成。此时,必须进行进一步配置以添加未跟踪的项目,包括:基本接口、资源包、基于 BeanInfo 的反射等。有关此过程的更多信息,请参阅 Graal 文档。
即使所有使用的类都必须编译为 AOT 到本机映像中,Web 应用程序仍必须保持不变,并继续将所有需要的类和 JAR 包含在 WEB-INF
文件夹中。虽然这些类不会实际运行或加载,但需要访问它们。
构建本机映像
如果一切正常,现在可以使用 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 都开箱即用地支持本机映像。
在撰写此文档时,JULI 不受支持,因为日志管理器配置属性不受 Graal 支持,此外还有一些静态初始化程序问题,而应使用常规的 java.util.logging 记录器和实现。
如果使用默认的 server.xml 文件,则必须从配置中删除一些服务器侦听器,因为它们与本机映像不兼容,例如 JMX 侦听器(JMX 不受支持)和泄漏预防侦听器(使用 Graal 中不存在的内部代码)。
缺少更好的 Tomcat 功能的项目
- java.util.logging LogManager:未实现通过系统属性进行配置,因此必须使用标准 java.util.logging 而不是 JULI
- 静态链接配置:tomcat-native 无法静态链接