weblogic92连接池的连接数异常问题(1) - 豆豆网
ERROR - Could not release connection to pool:java.lang.NullPointerException
Could not get JDBC Connection; nested exception is weblogic.jdbc.extensions.PoolDisabledSQLException: weblogic.common.resourcepool.ResourceDisabledException: Pool bjjcsj is disabled, cannot allocate resources to applications..
ERROR - Hibernate operation: Cannot open connection; uncategorized SQLException for SQL [???]; SQL state [null]; error code [0]; weblogic.common.resourcepool.ResourceDisabledException: Pool bjjcsj is disabled, cannot allocate resources to applications..; nested exception is weblogic.jdbc.extensions.PoolDisabledSQLException: weblogic.common.resourcepool.ResourceDisabledException: Pool bjjcsj is disabled, cannot allocate resources to applications.. (LogHandler.java:72)
pool被disabled的原因大致有3:
1、连接被手工强制suspend;
2、网络不通;
3、程序在执行过程中被挂起;
首先我们看看这个pool为什么会被disable? 手工强制suspend连接池、数据库关闭、网络不稳定等因素都可能成为connection pool被disable的诱因。从客户的日志中,我能看到大量的如下异常,
1:java.net.SocketException: 管道已断开 (errno:32)
2:weblogic.common.resourcepool.ResourceDisabledException: Pool JDBC Data Source-0 is disabled, cannot allocate resources to applications.
根据上面的异常,首先跟客户确认是否存在过数据库关闭、强制disable connection的操作,这些都被客户否定了,那么最大可能的原因就是网络不稳定,网络是好时坏的话,很容易造成weblogic连接池中到 database server的连接中断,从而导致connection pool被disable。
一个被disable的connection pool我们需要手工resume吗?比如数据库因为某些原因而突发关闭,数据库恢复后,我们是否需要手工去resume这个pool?不需要,weblogic内部实现了连接池的自我健康检查功能,对于disable的connection pool,weblogic会每隔5秒钟(DEFAULT_SCAN_UNIT)去做一次连接尝试(尝试创建一个物理连接,如果连接成功,那么这个连接会被直接放入连接池中,我们的问题就处在这儿),我们通过下面的复现过程来看看具体原因:
1:配置一个datasource,connection的连接数具体配置如下:
那么我们能不能通过参数配置不让connection pool不作disable呢?我们前面所提到的两个参数:CountOfTestFailuresTillFlush、 CountOfRefreshFailuresTillDisable,可以实现这样的要求:
1 <internal-properties>
2 <property>
3 <name>CountOfTestFailuresTillFlush</name>
4 <value>10</value>
5 </property>
6 <property>
7 <name>CountOfRefreshFailuresTillDisable</name>
8 <value>20</value>
9 </property>
10 </internal-properties>
internal-properties用于定义一些weblogic internal的参数,这些参数无法在console上做配置。除了上面的这两个参数,我们还可以通过internal-properties配置如下几个参数:
TestConnectionsOnCreate
TestConnectionsOnRelease
HighestNumUnavailable
SecurityCacheTimeoutSeconds
通过上述分析,我们可以看到这个问题不是weblogic的bug,而是因为网络问题导致connection pool被disable,要彻底解决这个问题,可以通过网络分析工具查出网络问题,进而解决我们看到的这种现象。
CXF入门教程(5) -- webService异步调用模式 - NearEast的专栏 - 博客频道 - CSDN.NET
除了教程(3)中介绍的常见的同步调用模式,CXF还支持如下两种形式的异步调用模式:
- 轮询方法(Polling approach) - 这种情况下调用远程方法,我们可以调用一个特殊的方法;该方法没有输出参数,但是返回一个 javax.xml.ws.Response 实例。可以轮询该 Response 对象(继承自 javax.util.concurrency.Future 接口)来检查是否有应答消息到达。
- 回调方法(Callback approach) -这种情况下调用远程方法,我们调用另外一个特殊的方法:该方法使用一个回调对象(javax.xml.ws.AsyncHandler类型)的引用作为一个参数。只要有应答消息到达客户端,CXF运行时就会回调该 AsyncHandler 对象,并将应答消息的内容传给它。
下面是两种异步调用的方法的描述和示例代码。
异步调用示例使用的契约
下面展示的是异步调用示例中使用的WSDL契约,为保证教程的连续性,本文使用的是前面教程(1)中生成的HelloWorld服务的WSDL契约。
- <?xml version="1.0" ?>
- <wsdl:definitions name="HelloWorld"
- targetNamespace="http://service.server.cxf.test.neareast.com/"
- xmlns:ns1="http://schemas.xmlsoap.org/soap/http" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
- xmlns:tns="http://service.server.cxf.test.neareast.com/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <wsdl:types>
- <xs:schema attributeFormDefault="unqualified"
- elementFormDefault="unqualified" targetNamespace="http://service.server.cxf.test.neareast.com/"
- xmlns:tns="http://service.server.cxf.test.neareast.com/" xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <xs:element name="IntegerUserMap" type="tns:IntegerUserMap"></xs:element>
- <xs:complexType name="User">
- <xs:sequence>
- <xs:element minOccurs="0" name="name" type="xs:string"></xs:element>
- </xs:sequence>
- </xs:complexType>
- <xs:complexType name="IntegerUserMap">
- <xs:sequence>
- <xs:element maxOccurs="unbounded" minOccurs="0" name="entry"
- type="tns:IdentifiedUser"></xs:element>
- </xs:sequence>
- </xs:complexType>
- <xs:complexType name="IdentifiedUser">
- <xs:sequence>
- <xs:element name="id" type="xs:int"></xs:element>
- <xs:element minOccurs="0" name="user" type="tns:User"></xs:element>
- </xs:sequence>
- </xs:complexType>
- <xs:element name="sayHi" type="tns:sayHi"></xs:element>
- <xs:complexType name="sayHi">
- <xs:sequence>
- <xs:element minOccurs="0" name="text" type="xs:string"></xs:element>
- </xs:sequence>
- </xs:complexType>
- <xs:element name="sayHiResponse" type="tns:sayHiResponse"></xs:element>
- <xs:complexType name="sayHiResponse">
- <xs:sequence>
- <xs:element minOccurs="0" name="return" type="xs:string"></xs:element>
- </xs:sequence>
- </xs:complexType>
- <xs:element name="sayHiToUser" type="tns:sayHiToUser"></xs:element>
- <xs:complexType name="sayHiToUser">
- <xs:sequence>
- <xs:element minOccurs="0" name="arg0" type="tns:User"></xs:element>
- </xs:sequence>
- </xs:complexType>
- <xs:element name="sayHiToUserResponse" type="tns:sayHiToUserResponse"></xs:element>
- <xs:complexType name="sayHiToUserResponse">
- <xs:sequence>
- <xs:element minOccurs="0" name="return" type="xs:string"></xs:element>
- </xs:sequence>
- </xs:complexType>
- <xs:element name="getUsers" type="tns:getUsers"></xs:element>
- <xs:complexType name="getUsers">
- <xs:sequence></xs:sequence>
- </xs:complexType>
- <xs:element name="getUsersResponse" type="tns:getUsersResponse"></xs:element>
- <xs:complexType name="getUsersResponse">
- <xs:sequence>
- <xs:element minOccurs="0" name="return" type="tns:IntegerUserMap"></xs:element>
- </xs:sequence>
- </xs:complexType>
- </xs:schema>
- </wsdl:types>
- <wsdl:message name="getUsers">
- <wsdl:part element="tns:getUsers" name="parameters">
- </wsdl:part>
- </wsdl:message>
- <wsdl:message name="sayHi">
- <wsdl:part element="tns:sayHi" name="parameters">
- </wsdl:part>
- </wsdl:message>
- <wsdl:message name="sayHiToUser">
- <wsdl:part element="tns:sayHiToUser" name="parameters">
- </wsdl:part>
- </wsdl:message>
- <wsdl:message name="sayHiToUserResponse">
- <wsdl:part element="tns:sayHiToUserResponse" name="parameters">
- </wsdl:part>
- </wsdl:message>
- <wsdl:message name="sayHiResponse">
- <wsdl:part element="tns:sayHiResponse" name="parameters">
- </wsdl:part>
- </wsdl:message>
- <wsdl:message name="getUsersResponse">
- <wsdl:part element="tns:getUsersResponse" name="parameters">
- </wsdl:part>
- </wsdl:message>
- <wsdl:portType name="iHelloWorld">
- <wsdl:operation name="sayHi">
- <wsdl:input message="tns:sayHi" name="sayHi">
- </wsdl:input>
- <wsdl:output message="tns:sayHiResponse" name="sayHiResponse">
- </wsdl:output>
- </wsdl:operation>
- <wsdl:operation name="sayHiToUser">
- <wsdl:input message="tns:sayHiToUser" name="sayHiToUser">
- </wsdl:input>
- <wsdl:output message="tns:sayHiToUserResponse" name="sayHiToUserResponse">
- </wsdl:output>
- </wsdl:operation>
- <wsdl:operation name="getUsers">
- <wsdl:input message="tns:getUsers" name="getUsers">
- </wsdl:input>
- <wsdl:output message="tns:getUsersResponse" name="getUsersResponse">
- </wsdl:output>
- </wsdl:operation>
- </wsdl:portType>
- <wsdl:binding name="HelloWorldSoapBinding" type="tns:iHelloWorld">
- <soap:binding style="document"
- transport="http://schemas.xmlsoap.org/soap/http"></soap:binding>
- <wsdl:operation name="sayHi">
- <soap:operation soapAction="" style="document"></soap:operation>
- <wsdl:input name="sayHi">
- <soap:body use="literal"></soap:body>
- </wsdl:input>
- <wsdl:output name="sayHiResponse">
- <soap:body use="literal"></soap:body>
- </wsdl:output>
- </wsdl:operation>
- <wsdl:operation name="sayHiToUser">
- <soap:operation soapAction="" style="document"></soap:operation>
- <wsdl:input name="sayHiToUser">
- <soap:body use="literal"></soap:body>
- </wsdl:input>
- <wsdl:output name="sayHiToUserResponse">
- <soap:body use="literal"></soap:body>
- </wsdl:output>
- </wsdl:operation>
- <wsdl:operation name="getUsers">
- <soap:operation soapAction="" style="document"></soap:operation>
- <wsdl:input name="getUsers">
- <soap:body use="literal"></soap:body>
- </wsdl:input>
- <wsdl:output name="getUsersResponse">
- <soap:body use="literal"></soap:body>
- </wsdl:output>
- </wsdl:operation>
- </wsdl:binding>
- <wsdl:service name="HelloWorld">
- <wsdl:port binding="tns:HelloWorldSoapBinding" name="HelloWorldImplPort">
- <soap:address location="http://localhost:9000/helloWorld"></soap:address>
- </wsdl:port>
- </wsdl:service>
- </wsdl:definitions>
生成异步 stub 代码
异步调用需要额外的stub代码(例如,服务端点接口中定义的专用的异步方法)。然而,这些特殊的stub代码不是默认生成的。要想打开异步特性,并生成必不可少的stub代码,我们必须使用WSDL 2.0规范的自定义映射特性。
自定义使我们能够改变 wsdl2java 工具生成stub代码的方式。特别地,它允许我们修改WSDL到Java的映射,并打开某些特性。在这里,自定义的作用是打开异步调用特性。自定义是用一个绑定声明规定的,该声明是我们用一个 jaxws:bindings 标签(jaxws 前缀绑定到 http://java.sun.com/xml/ns/jaxws 命名空间)定义的。指定一个绑定声明有两种可选的方式:
- 外部绑定声明 - jaxws:bindings 元素被定义在WSDL契约之外的一个单独的文件。生成stub代码的时候,我们需要对wsdl2java 工具指定绑定声明文件的位置。
- 嵌入式绑定声明 - 我们也可以直接把jaxws:bindings 元素嵌入到 WSDL 契约中,把它当做WSDL的扩展。在这种情况下,jaxws:bindings 的设置仅对直接的父元素起作用。
本文只考虑第一种方法,即外部绑定声明。一个打开了异步调用开关的绑定声明文件的模版如下所示:
- <bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
- wsdlLocation="http://localhost:9000/helloWorld?wsdl"
- xmlns="http://java.sun.com/xml/ns/jaxws">
- <bindings node="wsdl:definitions">
- <enableAsyncMapping>true</enableAsyncMapping>
- </bindings>
- </bindings>
其中的wsdlLocation指定了该绑定声明影响的WSDL文件的位置,可以是本地文件或一个URL。node节点是一个XPath 值,指定该绑定声明影响所影响的WSDL契约中的节点。 此处把node设为“wsdl:definitions”,表示我们希望对整个WSDL契约起作用。{jaxws:enableAsyncMapping}} 元素设置为true,用来使能异步调用特性。
如果我们只想对一个端口“iHelloWorld”生成异步方法,我们可以在前面的绑定声明中指定<bindings node="wsdl:definitions/wsdl:portType[@name='iHelloWorld']"> 。
接下来我们就可以使用wsdl2java命令来生成相应的带异步支持的stub代码了。为简单起见,假设绑定声明文件存储在本地文件async_binding.xml中,我们可以使用类似下面的命令:
wsdl2java -b async_binding.xml hello_world.wsdl
其中-b 选项用来指定绑定声明文件。通过这种方法生成stub代码之后,HelloWorld的服务端点接口定义如下:
- import java.util.concurrent.Future;
- import javax.jws.WebMethod;
- import javax.jws.WebParam;
- import javax.jws.WebResult;
- import javax.jws.WebService;
- import javax.xml.bind.annotation.XmlSeeAlso;
- import javax.xml.ws.AsyncHandler;
- import javax.xml.ws.RequestWrapper;
- import javax.xml.ws.Response;
- import javax.xml.ws.ResponseWrapper;
- @WebService(targetNamespace = "http://service.server.cxf.test.neareast.com/", name = "iHelloWorld")
- @XmlSeeAlso({ObjectFactory.class})
- public interface IHelloWorld {
- @RequestWrapper(localName = "sayHi", targetNamespace = "http://service.server.cxf.test.neareast.com/", className = "com.neareast.test.cxf.asyClient.WSDL2Java.SayHi")
- @ResponseWrapper(localName = "sayHiResponse", targetNamespace = "http://service.server.cxf.test.neareast.com/", className = "com.neareast.test.cxf.asyClient.WSDL2Java.SayHiResponse")
- @WebMethod(operationName = "sayHi")
- public Response<com.neareast.test.cxf.asyClient.WSDL2Java.SayHiResponse> sayHiAsync(
- @WebParam(name = "text", targetNamespace = "")
- java.lang.String text
- );
- @RequestWrapper(localName = "sayHi", targetNamespace = "http://service.server.cxf.test.neareast.com/", className = "com.neareast.test.cxf.asyClient.WSDL2Java.SayHi")
- @ResponseWrapper(localName = "sayHiResponse", targetNamespace = "http://service.server.cxf.test.neareast.com/", className = "com.neareast.test.cxf.asyClient.WSDL2Java.SayHiResponse")
- @WebMethod(operationName = "sayHi")
- public Future<?> sayHiAsync(
- @WebParam(name = "text", targetNamespace = "")
- java.lang.String text,
- @WebParam(name = "asyncHandler", targetNamespace = "")
- AsyncHandler<com.neareast.test.cxf.asyClient.WSDL2Java.SayHiResponse> asyncHandler
- );
- @WebResult(name = "return", targetNamespace = "")
- @RequestWrapper(localName = "sayHi", targetNamespace = "http://service.server.cxf.test.neareast.com/", className = "com.neareast.test.cxf.asyClient.WSDL2Java.SayHi")
- @WebMethod
- @ResponseWrapper(localName = "sayHiResponse", targetNamespace = "http://service.server.cxf.test.neareast.com/", className = "com.neareast.test.cxf.asyClient.WSDL2Java.SayHiResponse")
- public java.lang.String sayHi(
- @WebParam(name = "text", targetNamespace = "")
- java.lang.String text
- );
- @RequestWrapper(localName = "sayHiToUser", targetNamespace = "http://service.server.cxf.test.neareast.com/", className = "com.neareast.test.cxf.asyClient.WSDL2Java.SayHiToUser")
- @ResponseWrapper(localName = "sayHiToUserResponse", targetNamespace = "http://service.server.cxf.test.neareast.com/", className = "com.neareast.test.cxf.asyClient.WSDL2Java.SayHiToUserResponse")
- @WebMethod(operationName = "sayHiToUser")
- public Response<com.neareast.test.cxf.asyClient.WSDL2Java.SayHiToUserResponse> sayHiToUserAsync(
- @WebParam(name = "arg0", targetNamespace = "")
- com.neareast.test.cxf.asyClient.WSDL2Java.User arg0
- );
- @RequestWrapper(localName = "sayHiToUser", targetNamespace = "http://service.server.cxf.test.neareast.com/", className = "com.neareast.test.cxf.asyClient.WSDL2Java.SayHiToUser")
- @ResponseWrapper(localName = "sayHiToUserResponse", targetNamespace = "http://service.server.cxf.test.neareast.com/", className = "com.neareast.test.cxf.asyClient.WSDL2Java.SayHiToUserResponse")
- @WebMethod(operationName = "sayHiToUser")
- public Future<?> sayHiToUserAsync(
- @WebParam(name = "arg0", targetNamespace = "")
- com.neareast.test.cxf.asyClient.WSDL2Java.User arg0,
- @WebParam(name = "asyncHandler", targetNamespace = "")
- AsyncHandler<com.neareast.test.cxf.asyClient.WSDL2Java.SayHiToUserResponse> asyncHandler
- );
- @WebResult(name = "return", targetNamespace = "")
- @RequestWrapper(localName = "sayHiToUser", targetNamespace = "http://service.server.cxf.test.neareast.com/", className = "com.neareast.test.cxf.asyClient.WSDL2Java.SayHiToUser")
- @WebMethod
- @ResponseWrapper(localName = "sayHiToUserResponse", targetNamespace = "http://service.server.cxf.test.neareast.com/", className = "com.neareast.test.cxf.asyClient.WSDL2Java.SayHiToUserResponse")
- public java.lang.String sayHiToUser(
- @WebParam(name = "arg0", targetNamespace = "")
- com.neareast.test.cxf.asyClient.WSDL2Java.User arg0
- );
- @RequestWrapper(localName = "getUsers", targetNamespace = "http://service.server.cxf.test.neareast.com/", className = "com.neareast.test.cxf.asyClient.WSDL2Java.GetUsers")
- @ResponseWrapper(localName = "getUsersResponse", targetNamespace = "http://service.server.cxf.test.neareast.com/", className = "com.neareast.test.cxf.asyClient.WSDL2Java.GetUsersResponse")
- @WebMethod(operationName = "getUsers")
- public Response<com.neareast.test.cxf.asyClient.WSDL2Java.GetUsersResponse> getUsersAsync();
- @RequestWrapper(localName = "getUsers", targetNamespace = "http://service.server.cxf.test.neareast.com/", className = "com.neareast.test.cxf.asyClient.WSDL2Java.GetUsers")
- @ResponseWrapper(localName = "getUsersResponse", targetNamespace = "http://service.server.cxf.test.neareast.com/", className = "com.neareast.test.cxf.asyClient.WSDL2Java.GetUsersResponse")
- @WebMethod(operationName = "getUsers")
- public Future<?> getUsersAsync(
- @WebParam(name = "asyncHandler", targetNamespace = "")
- AsyncHandler<com.neareast.test.cxf.asyClient.WSDL2Java.GetUsersResponse> asyncHandler
- );
- @WebResult(name = "return", targetNamespace = "")
- @RequestWrapper(localName = "getUsers", targetNamespace = "http://service.server.cxf.test.neareast.com/", className = "com.neareast.test.cxf.asyClient.WSDL2Java.GetUsers")
- @WebMethod
- @ResponseWrapper(localName = "getUsersResponse", targetNamespace = "http://service.server.cxf.test.neareast.com/", className = "com.neareast.test.cxf.asyClient.WSDL2Java.GetUsersResponse")
- public com.neareast.test.cxf.asyClient.WSDL2Java.IntegerUserMap getUsers();
- }
除了原来的同步方法(如sayHi方法),sayHi操作的两个异步调用方法也被同时生成了:
- 返回值类型为Future<?>,有一个类型为javax.xml.ws.AsyncHandler的额外参数的sayHiAsync()方法 —— 该方法可用于异步调用的回调方式。
- 返回值类型为Response<GreetMeSometimeResponse>的sayHiAsync()方法 —— 该方法可用于异步调用的轮询方式。
回调方式和轮询方式的细节将在下面的章节讨论。为体现异步调用的特点,笔者修改了教程(1)中Helloworld服务的部分实现,在sayHiToUser()方法中加入了3秒钟的休眠,并增强了代码的鲁棒性,改动如下:
- public String sayHiToUser(User user) {
- String retVal = null;
- if(null == user){
- retVal = "Error: user object null !";
- }else{
- try{
- System.out.println("sleep for 3 seconds before return");
- Thread.sleep(3000);
- }catch(InterruptedException e){
- e.printStackTrace();
- }
- System.out.println("sayHiToUser called by: " + user.getName());
- users.put(users.size() + 1, user);
- retVal = "Hello " + user.getName();
- }
- return retVal;
- }
实现一个轮询方式的异步调用客户端
下面的代码演示了异步发送操作调用的轮询方式的实现。客户端是通过特殊的Java方法 _OperationName_Async(本例为sayHiAsync()方法)来调用这个操作的,该方法返回一个javax.xml.ws.Response<T> 对象,其中“T”是这个操作的响应消息的类型(本例中为SayHiResponse类型)。我们可以稍后通过轮询Response<T> 对象来检查该操作的响应消息是否已经到达。
- package com.neareast.test.cxf.asyClient.consumer;
- import java.util.concurrent.ExecutionException;
- import javax.xml.ws.Response;
- import com.neareast.test.cxf.asyClient.WSDL2Java.HelloWorld;
- import com.neareast.test.cxf.asyClient.WSDL2Java.IHelloWorld;
- import com.neareast.test.cxf.asyClient.WSDL2Java.SayHiResponse;
- public class BasicClientPolling {
- public static void main(String[] args) throws InterruptedException{
- HelloWorld server = new HelloWorld();
- IHelloWorld hello = server.getHelloWorldImplPort();
- Response<SayHiResponse> sayHiResponseResp = hello.sayHiAsync(System.getProperty("user.name"));
- while (!sayHiResponseResp.isDone()) {
- Thread.sleep(100);
- }
- try {
- SayHiResponse reply = sayHiResponseResp.get();
- System.out.println( reply.getReturn() );
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- }
- }
sayHiAsync()方法调用了sayHi操作,将输入参数传送到远程的服务,并返回javax.xml.ws.Response<SayHiResponse> 对象的一个引用。Response 类实现了标准的 java.util.concurrency.Future<T> 接口,该类设计用来轮询一个并发线程执行的任务的产出结果。本质上来说,使用Response对象来轮询有两种基本方法:
- Non-blocking polling(非阻塞轮询) - 尝试获得结果之前,调用非阻塞方法Response<T>.isDone()来检查响应消息是否到达,例如:
- <pre name="code" class="java"> User u = new User();
- //非阻塞式轮询
- u.setName(System.getProperty("user.name"));
- Response<SayHiToUserResponse> sayHiToUserResponseResp = hello.sayHiToUserAsync(u);
- while (!sayHiToUserResponseResp.isDone()) {
- Thread.sleep(100);
- }
- try {
- //如果没有前面isDone的检测,此处就退化为阻塞式轮询
- SayHiToUserResponse reply = sayHiToUserResponseResp.get();
- System.out.println( reply.getReturn() );
- } catch (ExecutionException e) {
- e.printStackTrace();
- }</pre><br>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- Blocking polling(阻塞轮询) - 立即调用Response<T>.get(),阻塞至响应到达(可以指定一个超时时长作为可选项)。例如,轮询一个响应,超时时长为60s:
- //阻塞式轮询
- u.setName("NearEast");
- sayHiToUserResponseResp = hello.sayHiToUserAsync(u);
- try {
- SayHiToUserResponse reply = sayHiToUserResponseResp.get(5L,java.util.concurrent.TimeUnit.SECONDS);
- System.out.println( reply.getReturn() );
- } catch (ExecutionException e) {
- e.printStackTrace();
- } catch (TimeoutException e) {
- e.printStackTrace();
- }
实现一个回调方式的异步调用客户端
发起异步操作调用的另一个可选方法是实现javax.xml.ws.AsyncHandler接口,派生出一个回调类。回调类必须实现 handleResponse() 方法,CXF运行时调用这个类将响应的到达通知给客户端。下面的代码给出了我们需要实现的 AsyncHandler 接口的轮廓。
package javax.xml.ws; public interface AsyncHandler<T> { void handleResponse(Response<T> res); }
本例使用一个测试用的回调类 SayHiToUserAsyHandler,代码如下:
- package com.neareast.test.cxf.asyClient.consumer;
- import java.util.concurrent.ExecutionException;
- import javax.xml.ws.AsyncHandler;
- import javax.xml.ws.Response;
- import com.neareast.test.cxf.asyClient.WSDL2Java.SayHiToUserResponse;
- public class SayHiToUserAsyHandler implements AsyncHandler<SayHiToUserResponse> {
- SayHiToUserResponse reply = null;
- @Override
- public void handleResponse(Response<SayHiToUserResponse> res) {
- try {
- reply = res.get();
- System.out.println( reply.getReturn() );
- } catch (ExecutionException e) {
- e.printStackTrace();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- public String getResponseText(){
- return reply.getReturn();
- }
- }
上述 handleResponse() 的实现只是简单地获取响应数据,并把它存放到成员变量reply中。额外的getResponseText() 方法是为了方便地从响应中提炼出主要的输出参数。
下面的代码演示了发起异步操作调用的回调方法。客户端通过特定的Java方法 _OperationName_Async()来调用相应的操作,该方法使用一个额外的AsyncHandler<T>类型的参数,并返回一个 java.util.concurrency.Future<?> 对象。
- package com.neareast.test.cxf.asyClient.consumer;
- import java.util.concurrent.Future;
- import com.neareast.test.cxf.asyClient.WSDL2Java.HelloWorld;
- import com.neareast.test.cxf.asyClient.WSDL2Java.IHelloWorld;
- import com.neareast.test.cxf.asyClient.WSDL2Java.User;
- public class BasicCallbackClient {
- public static void main(String[] args) throws InterruptedException{
- HelloWorld server = new HelloWorld();
- IHelloWorld hello = server.getHelloWorldImplPort();
- User u = new User();
- //非阻塞式轮询
- u.setName(System.getProperty("user.name"));
- SayHiToUserAsyHandler asyHandler = new SayHiToUserAsyHandler();
- Future<?> res = hello.sayHiToUserAsync(u, asyHandler);
- while (!res.isDone()) {
- Thread.sleep(100);
- }
- String reply = asyHandler.getResponseText();
- System.out.println( reply );
- }
- }
sayHiToUserAsync()方法返回的 Future<?> 对象只是用来检测一个响应是否已经到达的 —— 例如,通过调用response.isDone()来轮询。响应消息的值只在回调对象SayHiToUserAsyHandler 中可得。
本文配套的完整代码已经上传,包括用到的wsdl契约文件和绑定声明文件;本文涉及的异步调用客户端的代码放在com.neareast.test.cxf.asyClient包下,欢迎下载:http://download.csdn.net/detail/neareast/4421250。
CXF之用Dispatch处理异步调用实例 - fhd001的专栏 - 博客频道 - CSDN.NET
服务接口:
- package cxf.server;
- import javax.jws.WebService;
- @WebService
- public interface HelloWorld {
- String sayHi(String text);
- }
服务接口实现:
- package cxf.server;
- import javax.jws.WebService;
- @WebService(endpointInterface = "cxf.server.HelloWorld")
- public class HelloWorldImpl implements HelloWorld {
- public String sayHi(String text) {
- try {
- Thread.sleep(30);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- System.out.println("sayHi called");
- return "Hello " + text;
- }
- }
服务端配置:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
- http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
- <import resource="classpath:META-INF/cxf/cxf.xml" />
- <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
- <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
- <jaxws:server id="helloWorld" serviceClass="cxf.server.HelloWorld" address="/HelloWorld">
- <jaxws:serviceBean>
- <bean class="cxf.server.HelloWorldImpl"/>
- </jaxws:serviceBean>
- <jaxws:features>
- <bean class="org.apache.cxf.feature.LoggingFeature"/>
- </jaxws:features>
- </jaxws:server>
- </beans>
客户端调用1---轮询方式异步调用:
- package cxf.client;
- import java.io.InputStream;
- import java.net.URL;
- import javax.xml.namespace.QName;
- import javax.xml.soap.MessageFactory;
- import javax.xml.soap.SOAPMessage;
- import javax.xml.transform.dom.DOMSource;
- import javax.xml.ws.Dispatch;
- import javax.xml.ws.Response;
- import javax.xml.ws.Service;
- public final class Client1 {
- public static void main(String args[]) throws Exception {
- URL wsdlUrl = new URL("http://localhost:8085/cxf-dispatch-test/service/HelloWorld?wsdl");
- QName serviceName = new QName("http://server.cxf/", "HelloWorldService");
- Service service = Service.create(wsdlUrl,serviceName);
- QName portName = new QName("http://server.cxf/", "HelloWorldPort");
- Dispatch<DOMSource> disp = service.createDispatch(portName, DOMSource.class, Service.Mode.MESSAGE);
- InputStream input = Client1.class.getResourceAsStream("soap1.xml");
- MessageFactory factory = MessageFactory.newInstance ();
- SOAPMessage soapMessage = factory.createMessage(null, input);
- DOMSource dom = new DOMSource(soapMessage.getSOAPPart());
- //轮询方式
- Response<DOMSource> rsp = disp.invokeAsync(dom);
- while(!rsp.isDone()){
- Thread.sleep(5);
- System.out.println("sleep 5");
- }
- DOMSource domRsp = rsp.get();
- System.out.println(domRsp.getNode().getLastChild().getNodeName());
- System.out.println(domRsp.getNode().getLastChild().getTextContent());
- }
- }
客户端调用2---回调方式异步调用:
- package cxf.client;
- import java.io.InputStream;
- import java.net.URL;
- import java.util.concurrent.Future;
- import javax.xml.namespace.QName;
- import javax.xml.soap.MessageFactory;
- import javax.xml.soap.SOAPMessage;
- import javax.xml.ws.Dispatch;
- import javax.xml.ws.Service;
- public final class Client2 {
- public static void main(String args[]) throws Exception {
- URL wsdlUrl = new URL("http://localhost:8085/cxf-dispatch-test/service/HelloWorld?wsdl");
- QName serviceName = new QName("http://server.cxf/", "HelloWorldService");
- Service service = Service.create(wsdlUrl,serviceName);
- QName portName = new QName("http://server.cxf/", "HelloWorldPort");
- Dispatch<SOAPMessage> disp = service.createDispatch(portName, SOAPMessage.class, Service.Mode.MESSAGE);
- InputStream input = Client2.class.getResourceAsStream("soap1.xml");
- MessageFactory factory = MessageFactory.newInstance ();
- SOAPMessage soapMessage = factory.createMessage(null, input);
- MyAsyncHandler<SOAPMessage> handler = new MyAsyncHandler<SOAPMessage>();
- //回调方式
- Future<?> rsp = disp.invokeAsync(soapMessage, handler);
- while(!rsp.isDone()){
- Thread.sleep(5);
- System.out.println("aaaaaaa");
- }
- SOAPMessage soapRsp = (SOAPMessage)rsp.get();
- System.out.println(soapRsp.getSOAPBody().getNodeName());
- System.out.println(soapRsp.getSOAPBody().getLastChild().getTextContent());
- }
- }
回调方式的AsyncHandler实现类:
- package cxf.client;
- import javax.xml.ws.AsyncHandler;
- import javax.xml.ws.Response;
- public class MyAsyncHandler<T> implements AsyncHandler<T> {
- /**
- * 这个回调类必须实现handleResponse()方法,它被调用由CXF运行时通知客户端响应已经到达。
- */
- @Override
- public void handleResponse(Response<T> res) {
- System.out.println("eeeeee");
- }
- }