【问题标题】:JAXB unmarshalling is very slow in Spring Boot application run as jar/war在以 jar/war 运行的 Spring Boot 应用程序中,JAXB 解组非常慢
【发布时间】:2026-02-01 22:55:01
【问题描述】:

由于我们调用的是旧版 API,我们需要使用 JAXB 解组收到的数据。

但在 2 周内,整个过程确实需要 2-3 倍的时间。 这方面的代码没变,依赖一样,docker base image也是一样的。

在我的本地开发环境中,我没有问题。该问题仅在我们的 openshift 服务器上可见。

我们调用的端点的同事在他们的性能指标上没有发现任何差异。

这基本上是代码:

JAXBContext jaxbContext = jaxbContexts.get(ProductsResponse.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
ProductsResponse result = unmarshaller.unmarshal(new StringReader(xmlStr));

上下文被缓存,createUnmarshaller 应该是一个轻量级操作,如此处所述JAXB creating context and marshallers cost

但是大部分时间都在通过创建 SAXParser 进行解组时丢失

...

我不知道是什么导致了这个问题。我们目前正在努力用支持 JAXB 注释的 Jackson XMLMapper 替换此处的 JAXB。但由于 API 中有一些奇怪的结构,我们无法掌握,这会导致更多问题。

商务人士越来越不耐烦了。我不知道...

【问题讨论】:

    标签: java spring-boot jaxb sax


    【解决方案1】:

    我们发现了问题。我想在这里与您分享解决方案。

    当我从本地 Windows 机器中使用 java -jar ... 从构建的 war 文件运行 spring boot 应用程序时,我可以重现该问题。 unmarshaller.unmarshal 花了大约 20 秒

    在我看来,一些 SAX 或 Xerces 类是由 WebappClassLoader 加载的,它使用 org.apache.catalina.webresources.Cache。但不知何故,这些类是从 war 文件中为每个操作加载的。

    正如这里Tomcat 8 throwing - org.apache.catalina.webresources.Cache.getResource Unable to add the resource 所述,缓存可能很小。

    使用这段代码,我将大小从 10 增加到 100 mb

    @Bean
    public WebServerFactoryCustomizer prodTomcatCustomizer()
    {
        return (WebServerFactoryCustomizer<TomcatServletWebServerFactory>) factory -> factory.addContextCustomizers(
          context -> {
              final int cacheSize = 100 * 1024;
              StandardRoot standardRoot = new StandardRoot(context);
              standardRoot.setCacheMaxSize(cacheSize);
              context.setResources(standardRoot);
          });
    }
    

    它解决了这个问题。我多年来看到的最佳图表:

    不能 100% 确定导致问题的原因。也许其他一些发展只是导致缓存已满,这会导致在每次解组操作时从 war 文件中加载这些类时出现巨大的性能问题。

    我希望这可以帮助一些人在使用 jaxb 和 spring boot 时遇到性能问题。

    【讨论】:

    • 这与 Spring Boot 无关,在没有 Spring/Spring Boot 的常规战争中也会发生这种情况。
    • 好点,我会改变我的问题的标题
    • 但是如果这能解决问题,你为什么要建造战争而不是罐子?因为如果您部署战争文件,这不会解决问题,因为此代码仅在运行嵌入式 tomcat not 时使用你的外部Tomcat)。
    • 可能与此有关:*.com/questions/39234159/…
    最近更新 更多