代码之家  ›  专栏  ›  技术社区  ›  tster

Eclipse生成的Web服务客户端速度非常慢

  •  8
  • tster  · 技术社区  · 14 年前

    一些预先信息:

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

    我可以连接并使用Web服务,这与生成客户机的Visual Studio(C)很好。

    我使用Eclipse Web工具(新的& GT;其他-GT;Web服务-GT;Web服务客户端)生成了Java客户端。

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

    我已经在axis代码中调试了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秒。from-the-web服务非常短,所以不需要花太多时间来解析。

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

    我不能调试它,因为我没有源代码(而且我已经厌倦了在常用库中调试50个调用)。

    我目前正在运行profiler来包含来自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());
    }
    

    注意:两种创建执行器的方法都会发生相同的事情

    编辑2:

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

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

    我不能发布URL,因为我现在只是在一台机器上开发它。但是,这里是如果我转到 http://localhost:3456/Executer?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客户端更改为CommonHTTPClient,并使用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.jar common.codec.jar 到类路径。

    4 回复  |  直到 13 年前
        1
  •  1
  •   Dan Breslau    14 年前

    1)验证C和Java客户端向服务器发送完全相同的请求。如果你在使用码头,打开 request logging 可能会给你所需要的数据。

    2)一旦SAX解析器开始在客户机上运行,它将进行回调,最终直接或间接调用生成的客户机中的方法。您应该能够在开始和结束时设置断点(和/或 return s)生成的客户端方法,并使用这些方法确定延迟发生的位置。

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

        2
  •  2
  •   Francesco Monari    13 年前

    我遇到了同样的问题,并解决了修改HTTP版本的问题。

    一种更简单的方法是,在stub类内部,对调用实例调用setproperty方法:

    _call.setProperty(MessageContext.HTTP_TRANSPORT_VERSION,HTTPConstants.HEADER_PROTOCOL_V11);
    
        3
  •  1
  •   Arash Motamedi    14 年前

    你的问题正是我现在面临的。有趣的是,我经历了几乎相同的周期(端点服务,.NET客户机工作正常,Eclipse生成的客户机需要花费5分钟来处理)。确实感谢您发布更新和解决方案。我不是Java悟性,所以我可以问你是否将解决方案应用于同一个Eclipse生成的客户端代码?或者你做了完全不同的事情?如果您修改了Eclipse生成的客户机代码,那么您到底在哪里添加了这些行?

    谢谢,我非常感谢你的帮助:)

    干杯, 阿拉什

        4
  •  0
  •   maximdim    14 年前

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

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