8

I'm working with a bit of a legacy component in which we interact with a SOAP web service (a technology which I absolutely, positively abhor) using some client code built using the JAXRPC-RI (reference implementation) library.

I'm interested in being able to set a timeout with the stubs so that in case the web services server does not reply within X seconds, the application isn't setting there forever waiting for a response.

I'm using to working with clients/stubs generated by Apache Axis, in which you can simply use org.apache.axis.client.Stub.setTimeout() to set a timeout.

For the life of me I can't figure out how to set a timeout when using Stubs created with JAXRPC-RI:

  • The port class I am instantiating extends com.sun.xml.rpc.client.StubBase and implements javax.xml.rpc.Stub and com.sun.xml.rpc.spi.runtime.StubBase.
  • The JavaDocs for none of these classes mention any sort of timeout or method to do this.
  • Trying code like stub._setProperty("axis.connection.timeout", 1000); results in an exception at runtime: javax.xml.rpc.JAXRPCException: Stub does not recognize property: axis.connection.timeout

Does anyone have any ideas on how to set/enforce a timeout when using a JAXRPC-RI client? Is it even possible?

4

8 回答 8

4

您可能有运气设置属性,例如sun.net.client.defaultConnectTimeoutor sun.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" ...
于 2009-06-07T15:45:49.120 回答
2

我不确定为什么这个特定的 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 类。覆盖 _getTransport() 方法以返回您在步骤 (1) 中创建的 ClientTransport 类的新实例。
  3. 用您自己的扩展客户端 _Impl 类。覆盖 get...Port() 方法,以便它使用您在步骤 (2) 中创建的存根,而不是生成的存根。
  4. 修改您编写的调用 Web 服务的客户端代码,使其使用您在步骤 (2) 中创建的 Stub 和您在步骤 (3) 中创建的 _Impl。

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

于 2010-11-04T17:08:50.537 回答
1

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

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

于 2010-11-25T12:03:13.610 回答
1

我知道您正在使用 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但它错误地指出超时以秒为单位。它实际上以毫秒为单位!

于 2012-07-31T09:20:17.440 回答
0

射线,

感谢您的输入。听起来您的方法更优越,因为它将避免几个无关的步骤。我得看看。但是,除非我遗漏了什么,否则我不相信正在创建额外的 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;
   }
}
于 2010-12-07T16:49:48.630 回答
0

我只是要尝试获得赏金,所以如果我完全走错了路,请不要开枪:) 如果您的应用程序“永远设置在那里等待响应”,那么您可以单独执行请求线程,在产生你的之后,requestThread你可以说requestThread.join(max_time_to_wait);下一个调用会检查 requestThread 是否还活着,如果它那么尝试杀死它。

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

于 2009-06-02T15:10:16.943 回答
0

这个问题可能有点晚了,但我今天遇到了这个问题。基于 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 提出的基本相同,但覆盖性稍差(在连接工厂的帮助下)。

于 2015-09-22T10:22:01.070 回答
-1

你应该使用:

import javax.xml.rpc.Stub;

...


int timeout = <number of milliseconds>;

((Stub) port)._setProperty(
                "axis.connection.timeout",
                timeout);
于 2013-08-26T13:59:55.070 回答