spring-boot-starter-ws 在 运行 作为 jar 时的性能

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

我们注意到当 运行 为

时,SOAP 网络服务似乎 运行 更快
spring-boot:run

与我们为部署和 运行ning

打包 JAR 不同
java -jar mySpringApp.jar

加速大约是 2-3 倍,所以显然我们希望我们的现场环境能够这样。

为了验证这不是我们应用程序中的内容,我已经使用 spring guide

中的示例应用程序进行了尝试

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

用 JMeter 测试它显示了同样的加速。我已经在 Windows 7 Java 1.8.0_31 和 Ubuntu 14.04 平台上用 1.8.0_45-b14.

测试了这个

这似乎只是 soap 服务的情况,简单 html 没有显示出任何显着的性能差异。知道是什么原因造成的吗?

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

at org.springframework.boot.loader.LaunchedURLClassLoader.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.hasNext(ServiceLoader.java:474)
at javax.xml.transform.FactoryFinder.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.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.hasNext(ServiceLoader.java:474)
at javax.xml.parsers.FactoryFinder.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 service provider discovery mechanism 定位,这涉及在 META-INF/services 下搜索某些资源。该搜索的性能对从中查找这些资源的 class 加载器的特性非常敏感。这就是为什么您会看到 mvn spring-boot:run 和使用可执行 JAR 之间的区别。特别是,可执行 JAR 包含嵌入式 JAR,从这些嵌入式 JAR 中查找资源非常昂贵。对于 mvn spring-boot:run 情况并非如此,这解释了为什么它更快。

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

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

你还需要添加如下依赖:

    <dependency>
        <groupId>org.apache.ws.commons.axiom</groupId>
        <artifactId>axiom-impl</artifactId>
        <version>1.2.15</version>
    </dependency>