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

我正在使用一些遗留组件,其中我们使用一些使用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); 在运行时导致exception: 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服务,以便它使用您在步骤(2)中创建的存根和您在步骤(3)中创建的_Impl。

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

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

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

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

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

射线,

感谢您的输入。 听起来你的方法很优越,因为它可以避免一些无关紧要的步骤。 我得去看看。 但是,除非我遗漏了一些内容,否则我不相信会创建额外的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; } } 

我知道你正在使用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提出的解决方案(感谢它!),我想出了以下内容:

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

你应该使用:

 import javax.xml.rpc.Stub; ... int timeout = ; ((Stub) port)._setProperty( "axis.connection.timeout", timeout);