Spring 启动 servlet 在 Tomcat 中显示性能问题,但在 Jetty 中没有

Spring boot servlet shows performance problems in Tomcat but not Jetty

我有一个 spring 启动 java servlet,它在 Jetty 下 运行 很好,但是在 运行 在 Tomcat 下有性能问题,这是我们的目标部署环境。

  1. JAXB 解组出现瓶颈,因为 ServiceLoader 花费大量时间查找要使用的 TransformerFactory 实现。 (YourKit profiling showing the look up for the TransformerFactory implementation)
  2. Saxon 是转换实现并且 jar 包含在 tomcat/webapps/myapp/WEB-INF/lib 中并且具有正确的 META-INF/services 文件
  3. 使用 Jetty 作为 servlet 容器时不存在此问题
  4. 我已经在 J​​etty 和 Tomcat 下确认 运行 我从正确的 jar 中获得了 TransformerFactory 的正确实现
  5. 将映射显式添加到 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 实现,并在 运行 时做出选择。