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

时间:2009-04-30 18:50:32

标签: java web-services java-ee soap jax-rpc

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

我对能够使用存根设置超时感兴趣,以便万一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客户端时如何设置/强制执行超时有任何想法?它甚至可能吗?

8 个答案:

答案 0 :(得分:4)

您可能有运气设置属性,例如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" ...

答案 1 :(得分: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类扩展客户端Stub类。重写_getTransport()方法以返回在步骤(1)中创建的ClientTransport类的新实例。
  3. 使用您自己的方法扩展客户端_Impl类。重写get ... Port()方法,以便它使用您在步骤(2)中创建的存根而不是生成的存根。
  4. 修改您编写的客户端代码以调用Web Service,以便它使用您在步骤(2)中创建的存根和您在步骤(3)中创建的_Impl。
  5. 注意:确保您通过wscompile(Ant脚本?)生成Stubs的任何内容都不会覆盖您刚刚创建/修改的3个Java类。将它们移动到不同的包可能是有意义的,这样它们就不会被覆盖。

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

我只是想尝试获得赏金,所以如果我完全走错了路,请不要开枪。:)如果你的应用程序“在那里永远等待响应”,那么你可以做到这一点在一个单独的线程中,在产生requestThread之后你可以说requestThread.join(max_time_to_wait);,下一次调用将检查requestThread是否仍然存活,如果是,则尝试杀死它。

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

答案 4 :(得分: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;
   }
}

答案 5 :(得分:0)

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

答案 6 :(得分: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提出的基本相同,但有一点不太重要(在连接工厂的帮助下)。

答案 7 :(得分:-1)

您应该使用:

import javax.xml.rpc.Stub;

...


int timeout = <number of milliseconds>;

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