Andreas Radauer
Andreas Radauer

Reputation: 1133

JAXB unmarshalling is very slow in Spring Boot application run as jar/war

Because of a legacy API what we are calling, we need to do unmarshal the received data with JAXB.

But for 2 weeks the whole process does take 2-3 times as long. Code in this area has not changed, dependencies are the same, and docker base image is the same.

In my local dev environment I have no issue. The problem is just visible on our servers in openshift.

And colleagues from the endpoint we are calling see no difference in their performance metrics.

This is basically the code:

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

Context is cached and createUnmarshaller should be a lightweight operation as described here JAXB creating context and marshallers cost.

But most of the time is lost in unmarshal by creating the SAXParser enter image description here

...

enter image description here

I have no idea what caused the issue. We are currently working to replace JAXB here with Jackson XMLMapper with JAXB Annotation support. But because of some strange structures in the API, which is not in our hand, this causes more issues.

Business people are getting more and more impatient. I have no clue...

Upvotes: 2

Views: 2525

Answers (1)

Andreas Radauer
Andreas Radauer

Reputation: 1133

We found a the issues. I want to share the solution here with you.

I could reproduce the problem when I run the spring boot app from the built war file with java -jar ... from my local windows machine. unmarshaller.unmarshal took about 20 seconds

As I see it, some SAX or Xerces classes are loaded by the WebappClassLoader and it uses the org.apache.catalina.webresources.Cache. But somehow the classes are loaded for every operation from the war file.

And as described here Tomcat 8 throwing - org.apache.catalina.webresources.Cache.getResource Unable to add the resource the Cache could be to small.

With this code, I increased the size from 10 to 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);
      });
}

And it solved the issue. Best graph I saw for ages:

enter image description here

Not 100% sure what caused the issue. Maybe some other developments just caused the cache to be full and this lead to the massive performance problem loading this classes from the war file at every unmarshal operation.

I hope this could help somebody how has a performance problem using jaxb and spring boot.

Upvotes: 2

Related Questions