繁体   English   中英

使用JAXRPC-RI Web服务客户端时如何设置连接超时?

[英]How to set a connection timeout when using JAXRPC-RI web services client?

我正在使用一些遗留组件,我们使用JAXRPC-RI(参考实现)库构建的一些客户端代码与SOAP Web服务(我绝对,积极地厌恶的技术)进行交互。

我有兴趣能够使用存根设置超时,以便万一Web服务器在X秒内没有回复,应用程序不会在那里永远等待响应。

我正在使用Apache Axis生成的客户端/存根,您可以在其中使用org.apache.axis.client.Stub.setTimeout()来设置超时。

对于我的生活,我无法弄清楚在使用JAXRPC-RI创建的存根时如何设置超时:

  • 我实例化的端口类扩展了com.sun.xml.rpc.client.StubBase并实现了javax.xml.rpc.Stubcom.sun.xml.rpc.spi.runtime.StubBase
  • 这些类中的JavaDocs都没有提到任何类型的超时或方法来执行此操作。
  • 尝试使用stub._setProperty("axis.connection.timeout", 1000); 在运行时导致异常: javax.xml.rpc.JAXRPCException: Stub does not recognize property: axis.connection.timeout

有没有人对使用JAXRPC-RI客户端时如何设置/强制执行超时有任何想法? 它甚至可能吗?

您可能有运气设置属性,例如sun.net.client.defaultConnectTimeoutsun.net.client.defaultReadTimeout ,但这会引入系统范围的超时。

在代码中,使用字符串设置属性值:

System.setProperty("sun.net.client.defaultConnectTimeout", "1000");
System.setProperty("sun.net.client.defaultReadTimeout", "1000");

对于快速测试,可能更容易设置环境变量JAVA_OPTS或使用命令行:

java -Dsun.net.client.defaultConnectTimeout="1000" ...

我不确定为什么这个特殊的JAXRPC实现会让它很难设置超时。 也许,这是有充分理由的。 其他实现,比如Axis,我相信JAX-WS,让你只需在Stub上调用setTimeout()方法。 经过一些痛苦,我能够想出这个解决方案。 希望它会有所帮助。 您需要执行以下操作才能在基础URLConnection上设置超时:

  1. 创建一个新的ClientTransport类。 它应该扩展com.sun.xml.rpc.client.http.HttpClientTransport类。 重写createHttpConnection(String,SOAPMessageContext)方法。 调用super.createHttpConnection(),它将返回HttpURLConnection对象。 在HttpURLConnection对象上,您可以调用setReadTimeout(),这将强制客户端超时X毫秒。 完成后,返回修改后的HttpURLConnection对象。
  2. 使用您自己的Stub类扩展客户端Stub类。 重写_getTransport()方法以返回在步骤(1)中创建的ClientTransport类的新实例。
  3. 使用您自己的扩展客户端_Impl类。 重写get ... Port()方法,以便它使用您在步骤(2)中创建的存根而不是生成的存根。
  4. 修改您编写的客户端代码以调用Web Service,以便它使用您在步骤(2)中创建的存根和您在步骤(3)中创建的_Impl。

注意:确保您通过wscompile(Ant脚本?)生成Stubs的任何内容都不会覆盖您刚刚创建/修改的3个Java类。 将它们移动到不同的包可能是有意义的,这样它们就不会被覆盖。

我知道您正在使用Axis,但我很难为Weblogic找到相同的答案,因为您的问题标题和标签是通用的,这是我的解决方案。

在我实现生成的MyObject接口的客户端类中,我已经调整了getServicePort(),如下所示(注意我在这里也有安全性)。

protected MyObject getServicePort() throws java.rmi.RemoteException {
    if (port == null) {
        synchronized(this) {
            if (port == null) {
                try {
                    final MyObject_Impl service = new MyObject_Impl(wsdlURL);

                    // using a local variable until the object is completelly initialized
                    final MyObject localPort = service.getMyObjectPort();

                    // if username and password are provided: building a client which will include the 
                    // username and token
                    if (username != null && pwd != null) {
                        Stub localStub = ((Stub) localPort);

                        // We have UsernameToken Authentication too
                        localStub._setProperty(
                                WSSecurityContext.CREDENTIAL_PROVIDER_LIST, 
                                Collections.singletonList(
                                        new ClientUNTCredentialProvider(username.getBytes(), pwd.getBytes())));

                        if (timeout != null) {
                               log.debug("Setting timeout to " + timeout + " milliseconds");
                            localStub._setProperty("weblogic.wsee.transport.read.timeout", timeout);
                            localStub._setProperty("weblogic.wsee.transport.connection.timeout", timeout);
                        }
                    }

                    port = localPort;

                } catch (ServiceException e) {
                    throw new RemoteException("Could not initialize client to MyObject service", e);
                }
            }
        }
    }
    return port;
}

Oracle文档位于: http//docs.oracle.com/cd/E12840_01/wls/docs103/webserv_rpc/client.html#wp241849但它错误地指出超时是以秒为单位。 它实际上是以毫秒为单位!

Yevgeniy Treyvus的答案非常好,但是会为每个SOAP调用创建一个新的HTTPUrlConnection。 我在测试他的方法时发现,可以设置ClientTransportFactory。 我现在使用CustomClientTransportFactory并将其设置在Stub上(将其转换为StubBase)。 然后一个人不需要第2步和第3步。

在步骤4中,然后设置他的新ClientTransportFactory,如下所示:((StubBase)myPort)._ setTransportFactory(new CustomClientTransportFactory());

也许这个问题有点迟了但我今天遇到了这个问题。 根据Yevgeniy Treyvus提出的解决方案(谢谢它!),我想出了以下内容:

((com.sun.xml.rpc.client.StubBase)myRemoteStub)._setTransportFactory(new ClientTransportFactory() {
    @Override
    public ClientTransport create() {
        return new HttpClientTransport() {
            @Override
            protected HttpURLConnection createHttpConnection(String endpoint, SOAPMessageContext context) throws IOException {
                HttpURLConnection conn = super.createHttpConnection(endpoint, context);
                conn.setConnectTimeout(2000);
                conn.setReadTimeout(2000);
                return conn;
            }
        };
    }
});

它基本上与Yevgeniy提出的相同,但有一点不太重要(在连接工厂的帮助下)。

射线,

感谢您的输入。 听起来你的方法很优越,因为它可以避免一些无关紧要的步骤。 我得去看看。 但是,除非我遗漏了一些内容,否则我不相信会创建额外的HttpConnection,因为YourClientTransport.createHttpConnection(String s,SOAPMessageContext ctx)应该覆盖HttpClientTransport:

public class YourClientTransport extends HttpClientTransport {
   @Override
   protected HttpUrlConnection createHttpConnection(String s, SOAPMessageContext ctx) throws IOException {
      HttpURLConnection httpURLConnection = super.createHttpConnection(s, ctx);
      httpURLConnection.setReadTimeout(1000);
      httpURLConnection.setConnectTimeout(1000);
      return httpURLConnection;
   }
}

我只是想收获赏金,所以如果我完全走错了轨道就不要开枪了:)如果你的应用程序“永远在那里设置等待响应”,那么你可以单独做出请求线程并在产生requestThread你可以说requestThread.join(max_time_to_wait); 下一个调用将检查requestThread是否仍然存在,如果是,那么尝试杀死它。

您的应用程序将在超时后继续运行,并且它不是最不优雅的解决方案......

你应该使用:

import javax.xml.rpc.Stub;

...


int timeout = <number of milliseconds>;

((Stub) port)._setProperty(
                "axis.connection.timeout",
                timeout);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM