Spring 启动 servlet 在 Tomcat 中显示性能问题,但在 Jetty 中没有
Spring boot servlet shows performance problems in Tomcat but not Jetty
我有一个 spring 启动 java servlet,它在 Jetty 下 运行 很好,但是在 运行 在 Tomcat 下有性能问题,这是我们的目标部署环境。
- JAXB 解组出现瓶颈,因为 ServiceLoader 花费大量时间查找要使用的 TransformerFactory 实现。 (YourKit profiling showing the look up for the TransformerFactory implementation)
- Saxon 是转换实现并且 jar 包含在 tomcat/webapps/myapp/WEB-INF/lib 中并且具有正确的 META-INF/services 文件
- 使用 Jetty 作为 servlet 容器时不存在此问题
- 我已经在 Jetty 和 Tomcat 下确认 运行 我从正确的 jar 中获得了 TransformerFactory 的正确实现
将映射显式添加到 Tomcat JAVA_OPTS 选项可解决问题:
-Djavax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl
已编辑:
我们在 Jetty 中的 xml fetch/transform 时间约为 5 秒,而在 Tomcat 下为 20 秒,这直接归因于 class 加载程序搜索我们的 TransformerFactory。
我可以通过在我们的 servlet 配置中明确指定 TransformerFactory 来解决问题,但我的问题仍然存在:
为什么 Tomcat 需要这个明确的 setProperty 而 Jetty 容器不需要?
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl");
return application.sources(Application.class);
}
抱歉,如果这是一个基本问题,我是一只学习 Java 和网络 apps/servlet 技巧的老 C++ 狗。
如果 JAXP 系统 属性 未设置标识工厂,则 JAXP 会在类路径中搜索 JAR 文件,其中包含 JAR 文件清单的服务文件中有关转换器工厂的信息。在类路径上有很多 JAR 的情况下,这种搜索可能会非常昂贵,最好避免这样做。对于您所看到的性能差异,最可能的解释是您的 Tomcat 配置比 Jetty 配置有更多的 JAR 文件要搜索。
到目前为止,实例化 Saxon 的最快方法是直接执行,并完全避免使用 JAXP 机制:
TransformerFactory factory = new net.sf.saxon.TransformerFactoryImpl()
这个也比较靠谱;如果您的应用程序是使用 Saxon 测试的,并且您不信任它 运行 与位于类路径上的任何旧 XSLT 1.0 处理器一起使用,那么您最好将 Saxon 的使用硬编码到应用程序源代码中。 JAXP 机制的唯一优势是您希望您的应用程序能够 运行 使用不同的 JAXP XSLT 实现,并在 运行 时做出选择。
我有一个 spring 启动 java servlet,它在 Jetty 下 运行 很好,但是在 运行 在 Tomcat 下有性能问题,这是我们的目标部署环境。
- JAXB 解组出现瓶颈,因为 ServiceLoader 花费大量时间查找要使用的 TransformerFactory 实现。 (YourKit profiling showing the look up for the TransformerFactory implementation)
- Saxon 是转换实现并且 jar 包含在 tomcat/webapps/myapp/WEB-INF/lib 中并且具有正确的 META-INF/services 文件
- 使用 Jetty 作为 servlet 容器时不存在此问题
- 我已经在 Jetty 和 Tomcat 下确认 运行 我从正确的 jar 中获得了 TransformerFactory 的正确实现
将映射显式添加到 Tomcat JAVA_OPTS 选项可解决问题:
-Djavax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl
已编辑: 我们在 Jetty 中的 xml fetch/transform 时间约为 5 秒,而在 Tomcat 下为 20 秒,这直接归因于 class 加载程序搜索我们的 TransformerFactory。
我可以通过在我们的 servlet 配置中明确指定 TransformerFactory 来解决问题,但我的问题仍然存在: 为什么 Tomcat 需要这个明确的 setProperty 而 Jetty 容器不需要?
public class Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl");
return application.sources(Application.class);
}
抱歉,如果这是一个基本问题,我是一只学习 Java 和网络 apps/servlet 技巧的老 C++ 狗。
如果 JAXP 系统 属性 未设置标识工厂,则 JAXP 会在类路径中搜索 JAR 文件,其中包含 JAR 文件清单的服务文件中有关转换器工厂的信息。在类路径上有很多 JAR 的情况下,这种搜索可能会非常昂贵,最好避免这样做。对于您所看到的性能差异,最可能的解释是您的 Tomcat 配置比 Jetty 配置有更多的 JAR 文件要搜索。
到目前为止,实例化 Saxon 的最快方法是直接执行,并完全避免使用 JAXP 机制:
TransformerFactory factory = new net.sf.saxon.TransformerFactoryImpl()
这个也比较靠谱;如果您的应用程序是使用 Saxon 测试的,并且您不信任它 运行 与位于类路径上的任何旧 XSLT 1.0 处理器一起使用,那么您最好将 Saxon 的使用硬编码到应用程序源代码中。 JAXP 机制的唯一优势是您希望您的应用程序能够 运行 使用不同的 JAXP XSLT 实现,并在 运行 时做出选择。