【问题标题】:Spring boot servlet shows performance problems in Tomcat but not JettySpring boot servlet 在 Tomcat 中显示性能问题,但在 Jetty 中没有
【发布时间】:2015-10-26 18:08:24
【问题描述】:

我有一个 spring boot 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. 我已经确认在 Jetty 和 Tomcat 下运行我从正确的 jar 中获得了 TransformerFactory 的正确实现
  5. 将映射显式添加到 Tomcat JAVA_OPTS 选项可以解决问题:

    -Djavax.xml.transform.TransformerFactory=net.sf.saxon.TransformerFactoryImpl

编辑: 我们在 Jetty 中的 xml 获取/转换时间大约是 5 秒,而在 Tomcat 下是 20 秒,这直接是由于类加载器搜索了我们的 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 和网络应用程序/servlet 技巧的老 C++ 狗。

【问题讨论】:

  • 第 4 个问题:“运行可执行的 .jar 或 .war 文件时”是指这些文件使用嵌入式码头而不是嵌入式 tomcat?
  • 当我进行测试时,他们使用的是嵌入式 Tomcat。在我所有的测试中,Jetty 一直都是外部的。
  • 我还阅读了有关 Jetty 和 Tomcat 的类加载器的文档。从这些来看,我不希望有任何区别,因为两个容器都必须遵守标准中设置的 servlet 容器的类加载器规则。
  • 太板了,你需要了解一下这个工厂是如何解决的,也许是注释扫描?为什么不以编程方式设置工厂?
  • 已编辑以尝试提供更多数据并缩小问题范围。我已经解决了这个问题,但感觉就像一个黑客,可能有更合适的方法来解决它。另外,我非常好奇为什么 Jetty 在没有额外设置的情况下也能正常工作,而只有 Tomcat 需要它。

标签: java tomcat spring-boot jetty saxon


【解决方案1】:

如果没有设置标识工厂的 JAXP 系统属性,那么 JAXP 会在类路径中搜索 JAR 文件,其中包含有关 JAR 文件清单的服务文件中的转换器工厂的信息。在类路径上有许多 JAR 的情况下,这种搜索可能会非常昂贵,并且绝对最好避免。对于您看到的性能差异,最可能的解释是您的 Tomcat 配置比 Jetty 配置要搜索的 JAR 文件多得多。

到目前为止,实例化 Saxon 的最快方法是直接进行,并完全避免使用 JAXP 机制:

TransformerFactory factory = new net.sf.saxon.TransformerFactoryImpl()

这样也比较靠谱;如果您的应用程序是用 Saxon 测试的,并且您不相信它可以在类路径上的任何旧 XSLT 1.0 处理器上运行,那么您最好将 Saxon 的使用硬编码到应用程序源代码中。如果您希望您的应用程序能够使用不同的 JAXP XSLT 实现运行,那么 JAXP 机制的唯一优势就是在运行时做出选择。

【讨论】:

  • 谢谢迈克尔。我认为这支持我对 System.setProperty 进行硬编码以定义我们正在使用的实现的解决方案。您提供的代码 sn-p 是否实际上为整个应用程序设置了 TransformerFactory?我问是因为我们无法直接控制何时/何地创建 TransformerFactory。基本上我想知道我是否应该在我的配置方法中用你的代码 sn-p 替换我的系统调用
  • 不,所提供的代码替换了任何执行TransformerFactory factory = TransformerFactory.newInstance() 的代码,并假定您可以访问应用程序中执行此操作的位置。如果您不能以这种方式更改代码,则使用系统属性是您的最佳选择,但缺点是它适用于整个应用程序,并且可能会更改仅经过测试的应用程序部分使用的 XSLT 引擎默认的 JDK 引擎并在使用其他引擎时中断。
猜你喜欢
  • 2019-08-25
  • 2018-03-17
  • 2013-05-26
  • 2015-10-07
  • 2014-07-23
  • 2014-01-01
  • 1970-01-01
  • 2017-03-23
  • 2017-03-12
相关资源
最近更新 更多