【问题标题】:JAX-WS client side is hanging for 30 secs when WSDL is too large当 WSDL 太大时,JAX-WS 客户端会挂起 30 秒
【发布时间】:2013-09-20 15:08:46
【问题描述】:

我对 JAX-WS Webservices 和 Apache CXF 有点陌生。我们正在开发一个简单的客户端-服务器系统,它们之间的通信是通过 JAX-WS Web 服务协议进行的。在服务器端,我们使用的是 Apache CXF 实现(因为使用了拦截器),在客户端它是正常的参考实现(jax-ws-rt)。

我的问题如下:当客户端首先创建服务时:

service = Service.create(uri.toURL(), new QName(targetNamespace, serviceName));

然后它通常会向服务器发送 GET 请求,以获取和处理 WSDL。首先是这样的:

GET .../services/ws/mainservice?wsdl

然后紧接着

GET .../services/ws/mainservice?wsdl=mainservice.wsdl

到目前为止,一切都很好。第三个请求是普通的 HTTP POST 请求,使用 SOAP,调用客户端调用的函数。

在 WSDL 变得太大之前一切正常。我可以从 Web 浏览器中查看大小,例如,使用上面的两个 GET 链接。当第二次 GET 请求的响应达到 100K 大小(浏览器中的 XML 响应)时,由于 Web 服务接口中声明的函数过多,会出现以下情况:客户端在第二次 GET 期间挂起约 30 秒请求,然后一切正常,函数运行。

我调试了一下,那个时候是哪一点被阻塞的,是在RuntimeWSDLParser.java,createReader()函数中,调用的时候:

private static XMLStreamReader createReader(URL wsdlLoc, Class<Service> serviceClass) throws IOException, XMLStreamException {
InputStream stream;
try {
    stream = wsdlLoc.openStream();
} catch (IOException io) {

}

这个文件在客户端的 jax-ws-rt.jar 中。

奇怪的是(至少对我来说,但我不是很熟悉)如果我用调试器到达这一行并立即跨过,那么它大约是 30 秒的阻塞。如果我等了 25 秒,然后我跨过去,那么只有 5 秒。所以似乎有一个柜台可以挂在某个地方。

另一件事:仅当我使用本地主机连接时才会出现此问题。如果我尝试使用与另一台计算机不同的客户端,并使用内部 IP 地址,则不会阻塞。当我尝试使用 TCPMon 并重定向端口时也不例外。

我希望我足够具体。任何帮助将不胜感激,我被这个问题困扰了好几天。提前致谢!

【问题讨论】:

    标签: java wsdl jax-ws blocking


    【解决方案1】:

    今天你很幸运!有两种选择:

    1. 在本地使用 WSDL 文档文件

      将 WSDL 文档文件和模式文件的副本保存到您的项目中。

      ClassLoader classloader = Thread.currentThread().getContextClassLoader();
      URL wsdlLocation = classloader.getResource("MyHelloService.wsdl");
      QName serviceName= new QName("http://test.com/", "MyHelloService");
      
      MyHelloService service = new MyHelloService(wsdlLocation, serviceName);
      service.sayHello("Test");
      
    2. 没有 WSDL 文档文件

      QName qname = new QName("http://thenamespace", "FooService");
      FooService service = new FooService(null, qname); // null for ignore WSDL
      Foo port = service.getFooPort();
      BindingProvider bindingProvider = (BindingProvider) port;
      bindingProvider.getRequestContext()
          .put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
          "http://foo.com/soap/fooBean");
      
      // Use the service
      Object obj = port.doSomething(param);
      

    另见:

    【讨论】:

    • 我在服务器端保存了一份副本,也为本地文件替换了导入,然后我调整了两个设置:1)我将 wsdlLocation 属性添加到实现 webservice 类中的@WebService 标记中, 2)从客户端我使用这个链接作为uri。很好用,谢谢!
    • 另外,我尽可能深入地调试了这个问题。在服务器端,jetty HttpConnection 中有一些同步(端点)块,它在返回数据后无法关闭输出流。所以在第一次请求之后,服务器端端点被阻塞 30 秒,这是读取超时的默认设置。然后,可以处理第二个请求。关于它取决于 wsdl 的大小,我认为这是一个码头错误。
    • 您看到服务客户端类中的static 块了吗?您可以修改它以避免加载远程 WSDL 并加载本地文件。
    猜你喜欢
    • 1970-01-01
    • 2013-12-04
    • 2013-11-17
    • 1970-01-01
    • 2011-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-09
    相关资源
    最近更新 更多