Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

spring-boot-starter-ws performance when run as jar

We've noticed in our that SOAP web-services seem to run faster when run as

spring-boot:run

as opposed to packaging up the JAR as we do for deployment and running

java -jar mySpringApp.jar

The speed up is in the order of 2-3x so obviously we would like this for our live environment.

To validate that this wasn't something in our app I've tried this with the sample app from the spring guide

git source https://github.com/spring-guides/gs-soap-service.git

Testing this with JMeter shows the same sort of speed up. I've tested this on both Windows 7 Java 1.8.0_31 and Ubuntu 14.04 platforms with 1.8.0_45-b14.

This only seems to be the case for soap services, simple html doesn't show any significant difference in performance. Any idea what could be causing this?

like image 816
user3702362 Avatar asked Jul 30 '15 17:07

user3702362


People also ask

How do I speed up spring boot REST API?

DB Use a fast connection pool like Hikari Ensure that your connection pool has the optimal configuration. Optimize queries. Faster response times means more threads available for processing. Thread management Correctly configuring the threadpool used for an executor and make a big difference in application performance.

What is the difference between spring boot starter and spring boot starter web?

It uses Spring MVC, REST, and Tomcat as a default embedded server. The single spring-boot-starter-web dependency can pull in all dependencies related to web development. It also reduces the count of build dependency.

Why is spring boot so slow?

When a Spring Boot Application has slow startup, it can be one or more beans and related dependencies taking longer to initialise and slowing down the entire process. Profiling Spring Boot application doesn't often help in diagnosing the startup issues.


1 Answers

I tested this and it appears that the application spends a significant amount of time in the following two code paths:

at org.springframework.boot.loader.LaunchedURLClassLoader$1.hasMoreElements(LaunchedURLClassLoader.java:110)
at sun.misc.CompoundEnumeration.next(CompoundEnumeration.java:45)
at sun.misc.CompoundEnumeration.hasMoreElements(CompoundEnumeration.java:54)
at java.util.ServiceLoader$LazyIterator.hasNextService(ServiceLoader.java:354)
at java.util.ServiceLoader$LazyIterator.hasNext(ServiceLoader.java:393)
at java.util.ServiceLoader$1.hasNext(ServiceLoader.java:474)
at javax.xml.transform.FactoryFinder$1.run(FactoryFinder.java:327)
at java.security.AccessController.doPrivileged(Native Method)
at javax.xml.transform.FactoryFinder.findServiceProvider(FactoryFinder.java:323)
at javax.xml.transform.FactoryFinder.find(FactoryFinder.java:299)
at javax.xml.transform.TransformerFactory.newInstance(TransformerFactory.java:106)
at com.sun.xml.internal.messaging.saaj.util.transform.EfficientStreamingTransformer.<init>(EfficientStreamingTransformer.java:68)
at com.sun.xml.internal.messaging.saaj.util.transform.EfficientStreamingTransformer.newTransformer(EfficientStreamingTransformer.java:420)
at com.sun.xml.internal.messaging.saaj.soap.EnvelopeFactory.createEnvelope(EnvelopeFactory.java:106)
at com.sun.xml.internal.messaging.saaj.soap.ver1_1.SOAPPart1_1Impl.createEnvelopeFromSource(SOAPPart1_1Impl.java:69)
at com.sun.xml.internal.messaging.saaj.soap.SOAPPartImpl.getEnvelope(SOAPPartImpl.java:128)
at org.springframework.ws.soap.saaj.SaajSoapMessageFactory.createWebServiceMessage(SaajSoapMessageFactory.java:189)
at org.springframework.ws.soap.saaj.SaajSoapMessageFactory.createWebServiceMessage(SaajSoapMessageFactory.java:60)
at org.springframework.ws.transport.AbstractWebServiceConnection.receive(AbstractWebServiceConnection.java:92)
at org.springframework.ws.transport.support.WebServiceMessageReceiverObjectSupport.handleConnection(WebServiceMessageReceiverObjectSupport.java:87)
at org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter.handle(WebServiceMessageReceiverHandlerAdapter.java:61)
at org.springframework.ws.transport.http.MessageDispatcherServlet.doService(MessageDispatcherServlet.java:293)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:869)

and

at org.springframework.boot.loader.LaunchedURLClassLoader$1.hasMoreElements(LaunchedURLClassLoader.java:110)
at sun.misc.CompoundEnumeration.next(CompoundEnumeration.java:45)
at sun.misc.CompoundEnumeration.hasMoreElements(CompoundEnumeration.java:54)
at java.util.ServiceLoader$LazyIterator.hasNextService(ServiceLoader.java:354)
at java.util.ServiceLoader$LazyIterator.hasNext(ServiceLoader.java:393)
at java.util.ServiceLoader$1.hasNext(ServiceLoader.java:474)
at javax.xml.parsers.FactoryFinder$1.run(FactoryFinder.java:293)
at java.security.AccessController.doPrivileged(Native Method)
at javax.xml.parsers.FactoryFinder.findServiceProvider(FactoryFinder.java:289)
at javax.xml.parsers.FactoryFinder.find(FactoryFinder.java:267)
at javax.xml.parsers.DocumentBuilderFactory.newInstance(DocumentBuilderFactory.java:120)
at com.sun.org.apache.xalan.internal.xsltc.trax.SAX2DOM.<init>(SAX2DOM.java:74)
at com.sun.org.apache.xalan.internal.xsltc.runtime.output.TransletOutputHandlerFactory.getSerializationHandler(TransletOutputHandlerFactory.java:199)
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.getOutputHandler(TransformerImpl.java:436)
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:342)
at com.sun.xml.internal.messaging.saaj.util.transform.EfficientStreamingTransformer.transform(EfficientStreamingTransformer.java:399)
at com.sun.xml.internal.messaging.saaj.soap.EnvelopeFactory.createEnvelope(EnvelopeFactory.java:108)
at com.sun.xml.internal.messaging.saaj.soap.ver1_1.SOAPPart1_1Impl.createEnvelopeFromSource(SOAPPart1_1Impl.java:69)
at com.sun.xml.internal.messaging.saaj.soap.SOAPPartImpl.getEnvelope(SOAPPartImpl.java:128)
at org.springframework.ws.soap.saaj.SaajSoapMessageFactory.createWebServiceMessage(SaajSoapMessageFactory.java:189)
at org.springframework.ws.soap.saaj.SaajSoapMessageFactory.createWebServiceMessage(SaajSoapMessageFactory.java:60)
at org.springframework.ws.transport.AbstractWebServiceConnection.receive(AbstractWebServiceConnection.java:92)
at org.springframework.ws.transport.support.WebServiceMessageReceiverObjectSupport.handleConnection(WebServiceMessageReceiverObjectSupport.java:87)
at org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter.handle(WebServiceMessageReceiverHandlerAdapter.java:61)
at org.springframework.ws.transport.http.MessageDispatcherServlet.doService(MessageDispatcherServlet.java:293)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:869)

The interesting lines are

at javax.xml.transform.TransformerFactory.newInstance(TransformerFactory.java:106)

and

at javax.xml.parsers.DocumentBuilderFactory.newInstance(DocumentBuilderFactory.java:120)

What this means is that for every request, the SAAJ implementation in the JRE requests a new TransformerFactory and a new DocumentBuilderFactory. These factories are located using the JDK 1.3 service provider discovery mechanism, which involves searching for certain resources under META-INF/services. The performance of that search is very sensitive to the characteristics of the class loaders from which these resources are looked up. That is why you see a difference between mvn spring-boot:run and using an executable JAR. In particular, the executable JAR contains embedded JARs and looking up resources from these embedded JARs is expensive. For mvn spring-boot:run this is not the case, which explains why it is faster.

Since this is ultimately a problem with the SAAJ implementation, one solution is to use Apache Axiom instead. To do this with the sample application from the spring guide, simply add the following code to WebServiceConfig:

    @Bean
    public SoapMessageFactory messageFactory() {
        return new AxiomSoapMessageFactory();
    }

You also need to add the following dependency:

    <dependency>
        <groupId>org.apache.ws.commons.axiom</groupId>
        <artifactId>axiom-impl</artifactId>
        <version>1.2.15</version>
    </dependency>
like image 56
Andreas Veithen Avatar answered Nov 10 '22 05:11

Andreas Veithen