您的位置:首页 > 其它

CXF入门教程(5) -- webService异步调用模式

2014-02-17 18:11 399 查看
除了教程(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()来检查响应消息是否到达,例如:

<div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><b>[java]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a><div style="position: absolute; left: 0px; top: 0px; width: 0px; height: 0px; z-index: 99; "><embed id="ZeroClipboardMovie_7" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="0" height="0" name="ZeroClipboardMovie_7" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=7&width=0&height=0" wmode="transparent"></div></div></div><ol start="1" class="dp-j"><li class="alt"><span><span>User u = </span><span class="keyword">new</span><span> User();  </span></span></li><li class=""><span>      </span></li><li class="alt"><span><span class="comment">//非阻塞式轮询</span><span>  </span></span></li><li class=""><span>u.setName(System.getProperty(<span class="string">"user.name"</span><span>));  </span></span></li><li class="alt"><span>Response<SayHiToUserResponse> sayHiToUserResponseResp = hello.sayHiToUserAsync(u);  </span></li><li class=""><span><span class="keyword">while</span><span> (!sayHiToUserResponseResp.isDone()) {  </span></span></li><li class="alt"><span>    Thread.sleep(<span class="number">100</span><span>);  </span></span></li><li class=""><span>}  </span></li><li class="alt"><span>      </span></li><li class=""><span><span class="keyword">try</span><span> {  </span></span></li><li class="alt"><span>    <span class="comment">//如果没有前面isDone的检测,此处就退化为阻塞式轮询</span><span>  </span></span></li><li class=""><span>    SayHiToUserResponse reply = sayHiToUserResponseResp.get();  </span></li><li class="alt"><span>    System.out.println( reply.getReturn() );  </span></li><li class=""><span>} <span class="keyword">catch</span><span> (ExecutionException e) {  </span></span></li><li class="alt"><span>    e.printStackTrace();  </span></li><li class=""><span>}  </span></li></ol></div><pre name="code" class="java" style="display: none; ">	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 接口的轮廓。

The javax.xml.ws.AsyncHandler Interface

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

本文参考自:http://cxf.apache.org/docs/developing-a-consumer.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: