以jar运行时的spring-boot-starter-ws性能

以jar运行时的spring-boot-starter-ws性能

问题描述:

我们已经注意到,SOAP Web服务的运行速度似乎更快

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

spring-boot:run

不同于像部署和运行那样打包JAR

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

java -jar mySpringApp.jar

速度提高了2-3倍,因此显然我们希望在我们的实时环境中使用它.

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源 https://github.com/spring-guides/gs- soap-service.git

使用JMeter进行测试可以显示相同的速度提升.我已经在Windows 7 Java 1.8.0_31和带有1.8.0_45-b14的Ubuntu 14.04平台上对此进行了测试.

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.

这似乎仅适用于肥皂服务,简单的html在性能上没有任何显着差异.知道是什么原因造成的吗?

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?

我对此进行了测试,看来该应用程序在以下两个代码路径中花费了大量时间:

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)

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)

有趣的台词是

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

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

这意味着对于每个请求,JRE中的SAAJ实现都请求一个新的TransformerFactory和一个新的DocumentBuilderFactory.这些工厂使用 JDK 1.3服务进行定位供应商发现机制,该机制涉及在META-INF/services下搜索某些资源.该搜索的性能对于从中查找这些资源的类加载器的特性非常敏感.这就是为什么您看到mvn spring-boot:run与使用可执行JAR之间的区别的原因.尤其是,可执行JAR包含嵌入式JAR,从这些嵌入式JAR查找资源非常昂贵.对于mvn spring-boot:run并非如此,这解释了为什么它更快.

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.

由于这最终是SAAJ实现的问题,所以一种解决方案是改用 Apache Axiom .要使用Spring Guide中的示例应用程序执行此操作,只需将以下代码添加到WebServiceConfig:

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>