【问题标题】:Eclipse Generated Web Service Client Extremely SlowEclipse 生成的 Web 服务客户端非常慢
【发布时间】:2010-12-31 10:53:39
【问题描述】:

一些前期信息:

我有一个 SOAP 服务(使用 JAX-WS(端点类)托管,但我认为这并不重要)。

我可以通过 Visual Studio 生成客户端 (C#) 很好地连接和使用 Web 服务。

我使用 Eclipse Web Tools(新 --> 其他 --> Web 服务 --> Web 服务客户端)生成了一个 java 客户端。

然后我写了一个JUnit测试来测试客户端。测试通过,但运行时间极长。每个服务调用需要 300 秒(给或需要几秒钟)。此外,计算机的速度有多快并不重要。如果我在我的工作速度非常慢的笔记本电脑上运行它,它所花费的时间就像我在我的快速家用机器上运行它一样。

我已经调试到 org.apache.axis.encoding.DeserializationContext 中以下函数的轴代码:

public void parse() throws SAXException
    {
        if (inputSource != null) {
            SAXParser parser = XMLUtils.getSAXParser();
            try {
                parser.setProperty("http://xml.org/sax/properties/lexical-handler", this);
                parser.parse(inputSource, this);

                try {
                    // cleanup - so that the parser can be reused.
                    parser.setProperty("http://xml.org/sax/properties/lexical-handler", nullLexicalHandler);
                } catch (Exception e){
                    // Ignore.
                }

不出意外,但是对 parser.parse() 的调用占用了 300 秒。来自 web 服务的文件很短,因此解析应该不会花费太多时间。

如果有人想知道,解析器的实际类型是com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl

我无法调试它,因为我没有源代码(而且我已经厌倦了深入调试常用库的 50 个调用)。

我目前正在运行分析器以包含来自 Sun 的软件包。完成后我会发布我的发现(添加所有这些包会显着减慢测试速度)

我正在运行Eclipse 3.5.1,我正在使用axis 1.4

编辑:

这里是 JUnit 测试:

@Test
public void testExecuter() throws IOException, InterruptedException, RemoteException, ServiceException
{
    //Listener l = new Listener(3456);
    //l.start();
    Executer exec = new ExecuterServiceLocator().getExecuterPort();
    //Executer exec = new ExecuterProxy("http://localhost:3456/Executer");
    System.out.println("executer created");
    _return remote = exec.execute("perl -e \"print 5\"", new EvAction[0]);
    System.out.println("after call 1");
    assertEquals("5", remote.getStdout());
    assertEquals("", remote.getStderr());
    assertEquals(0, remote.getReturnCode());
}

注意:创建 Executer 的两种方式都会发生相同的事情

编辑2:

这是我用来启动服务的代码:

public static void main(String[] args) {
    Endpoint.create(new Executer()).publish("http://localhost:3456/Executer");
}

我无法发布 URL,因为我现在只是在一台机器上开发它。但是,如果我转到http://localhost:3456/Executer?WSDL,这是生成的 WSDL

<!--
 Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.1.6 in JDK 6. 
-->
−
<!--
 Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.1.6 in JDK 6. 
-->
−
<definitions targetNamespace="http://executer/" name="ExecuterService">
−
<types>
−
<xsd:schema>
<xsd:import namespace="http://executer/" schemaLocation="http://localhost:3456/Executer?xsd=1"/>
</xsd:schema>
</types>
−
<message name="Execute">
<part name="parameters" element="tns:Execute"/>
</message>
−
<message name="ExecuteResponse">
<part name="parameters" element="tns:ExecuteResponse"/>
</message>
−
<message name="IOException">
<part name="fault" element="tns:IOException"/>
</message>
−
<message name="InterruptedException">
<part name="fault" element="tns:InterruptedException"/>
</message>
−
<portType name="Executer">
−
<operation name="Execute">
<input message="tns:Execute"/>
<output message="tns:ExecuteResponse"/>
<fault message="tns:IOException" name="IOException"/>
<fault message="tns:InterruptedException" name="InterruptedException"/>
</operation>
</portType>
−
<binding name="ExecuterPortBinding" type="tns:Executer">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
−
<operation name="Execute">
<soap:operation soapAction=""/>
−
<input>
<soap:body use="literal"/>
</input>
−
<output>
<soap:body use="literal"/>
</output>
−
<fault name="IOException">
<soap:fault name="IOException" use="literal"/>
</fault>
−
<fault name="InterruptedException">
<soap:fault name="InterruptedException" use="literal"/>
</fault>
</operation>
</binding>
−
<service name="ExecuterService">
−
<port name="ExecuterPort" binding="tns:ExecuterPortBinding">
<soap:address location="http://localhost:3456/Executer"/>
</port>
</service>
</definitions>

编辑:

我认为这可能会导致问题:

我使用 TCPMonitor 查看 SOAP 请求,我注意到客户端使用的是 HTTP/1.0,而服务器使用的是 HTTP/1.1,但我不知道这是否导致了问题。我目前正在尝试弄清楚如何让客户端使用 HTTP/1.1。

以下是 SOAP 消息,以防有人想知道:

POST /Executer HTTP/1.0
Content-Type: text/xml; charset=utf-8
Accept: application/soap+xml, application/dime, multipart/related, text/*
User-Agent: Axis/1.4
Host: USENBOONETL1C:2222
Cache-Control: no-cache
Pragma: no-cache
SOAPAction: ""
Content-Length: 354

<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body><Execute xmlns="http://executer/"><arg0 xmlns="">perl -e &quot;print 5&quot;</arg0></Execute></soapenv:Body></soapenv:Envelope>

以及回应:

HTTP/1.1 200 OK
Content-type: text/xml;
charset="utf-8"
Content-length: 266

<?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:ExecuteResponse xmlns:ns2="http://executer/"><return><stdout>5</stdout><stderr></stderr><returnCode>0</returnCode></return></ns2:ExecuteResponse></S:Body></S:Envelope>

编辑:

终于!原来将 HTTP 客户端更改为 CommonsHTTPClient 并使用 HTTP/1.1 解决了这个问题:

这是我添加到修复它的客户端的代码:

BasicClientConfig basicClientConfig = new BasicClientConfig();
SimpleChain simpleChain = new SimpleChain();

simpleChain.addHandler(new CommonsHTTPSender());
basicClientConfig.deployTransport("http", simpleChain);

ExecuterServiceLocator l = new ExecuterServiceLocator(basicClientConfig);
...

注意:您必须将common-httpclient.jarcommon.codec.jar 添加到类路径中。

【问题讨论】:

  • 会不会是您的 URL (xml.org/sax/properties/lexical-handler) 有问题,并且您在 5 分钟后遇到了超时?将解释为什么无论计算机速度如何,它总是需要相同的时间。
  • 我猜可能是这样,但我仍然得到正确的返回值,这看起来很奇怪。
  • 另一件让我认为这不是 URL 超时的事情是实际请求很快到达那里。我可以看到服务器立即执行命令。
  • 当您使用浏览器点击该 URL 时,该 URL 为 404。我用 Eclipse 生成的代码做了大量的 SOAP 客户端工作。 300 秒是一个太干净的延迟数字,除了超时之外什么都不是。您使用的 wsdl 是否公开可见?可以发一下吗?
  • 我同意这可能是超时,但我认为这可能是套接字读取超时。

标签: java eclipse web-services axis


【解决方案1】:

我遇到了同样的问题,并通过修改 http 版本解决了它。

一种更简单的方法是,在存根类中,调用 Call 实例的 setProperty 方法:

_call.setProperty(MessageContext.HTTP_TRANSPORT_VERSION,HTTPConstants.HEADER_PROTOCOL_V11);

【讨论】:

    【解决方案2】:

    1) 验证 C# 和 Java 客户端是否向服务器发送完全相同的请求。如果您使用 Jetty,打开 request logging 可能会为您提供所需的数据。

    2) 一旦 SAX 解析器开始在客户端上运行,它将进行回调,最终会直接或间接地调用生成的客户端中的方法。您应该能够在生成的客户端方法的开头和结尾(和/或returns)设置断点,并使用它们来确定延迟[s]发生的位置。

    (顺便说一句,在 SAX API 中,http://xml.org/sax/properties/lexical-handler 等 URL 用于本地标识属性名称;在该地址不会查找任何内容。有关详细信息,请参阅 http://xerces.apache.org/xerces2-j/properties.html。)

    【讨论】:

    • 这让我找到了正确的答案。我更新了我的问题以显示我是如何解决它的,以防有人想知道。
    【解决方案3】:

    你的问题正是我现在所面临的。有趣的是,我经历了几乎相同的周期(端点服务,.net 客户端工作正常,eclipse 生成的客户端需要 5 分钟才能处理)。确实,感谢您发布更新和解决方案。我不是一个精通java的人,所以请问您是否将该解决方案应用于相同的eclipse生成的客户端代码?还是你做了完全不同的事情?如果您修改了 eclipse 生成的客户端代码,您究竟在哪里添加了这些行?

    谢谢,非常感谢您的帮助:)

    干杯, 阿拉什

    【讨论】:

    • 我发布的让它工作的代码是你将放在你的代码中以实例化 Web 服务访问器的代码。您无需更改任何生成的代码。在您实际调用服务的地方,您需要在创建 ServiceLocator 时添加该 http 处理程序。
    • 太好了 :) 非常感谢。它现在完美运行。一旦我的声望达到 15,我肯定会投票赞成你的问题:D
    【解决方案4】:

    很可能是超时。可能是那个解析器试图从互联网(DTD、XSD 等)下载一些东西,但你在代理/防火墙后面。

    在运行测试时尝试获取服务器的堆栈跟踪以查看发生了什么(例如 jps/jstat)。

    【讨论】:

    • 我在家里和工作中都经历过这种情况。另外,我很确定服务器不是问题,因为当 Visual Studio 生成的客户端调用它时它很快。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-15
    • 2015-09-09
    • 2012-05-19
    • 1970-01-01
    • 2012-01-29
    • 2013-01-02
    相关资源
    最近更新 更多