前面博客中,我们通过WSDL创建的客户端几乎都是同步的,也就是从web服务端有响应返回或有一个异常抛出之前,调用将一直阻塞。另外JWS也支持客户端对web服务的非阻塞或异步方式调用(注:好像RPC样式的不支持异步调用)。
以前面的HelloWord为例,我们调用下面的命令:
% wsimport -s source -p hw3 http://localhost:7654/ts?wsdl -b custom.xml
为了创建非阻塞的客户端(或者异步的客户端),这里我们使用了定制化的绑定文件:custom.xml。custom.xml中的内容如下:
<jaxws:bindings wsdlLocation = "http://localhost:7654/ts?wsdl"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws">
<jaxws:enableAsyncMapping>true</jaxws:enableAsyncMapping>
</jaxws:bindings>
文档中将enableAsyncMapping属性值设置为true。这样生成的客户端代码如下:
HelloWord.java:
package hw3;
import java.util.concurrent.Future;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.Action;
import javax.xml.ws.AsyncHandler;
import javax.xml.ws.Holder;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.Response;
import javax.xml.ws.ResponseWrapper;
/**
* This class was generated by the JAX-WS RI.
* JAX-WS RI 2.2.4-b01
* Generated source version: 2.2
*/
@WebService(name = "HelloWord", targetNamespace = "http://ts.ch03/")
@XmlSeeAlso({
ObjectFactory.class
})
public interface HelloWord {
/**
* @param wh
* @param name
* @return
* returns javax.xml.ws.Response<hw3.SayHelloResponse>
*/
@WebMethod(operationName = "sayHello")
@RequestWrapper(localName = "sayHello", targetNamespace = "http://ts.ch03/",
className = "hw3.SayHello")
@ResponseWrapper(localName = "sayHelloResponse", targetNamespace = "http://ts.ch03/",
className = "hw3.SayHelloResponse")
public Response<SayHelloResponse> sayHelloAsync(
@WebParam(name = "name", targetNamespace = "")
String name,
@WebParam(name = "wh", targetNamespace = "")
String wh);
/**
* @param wh
* @param name
* @param asyncHandler
* @return
* returns java.util.concurrent.Future<? extends java.lang.Object>
*/
@WebMethod(operationName = "sayHello")
@RequestWrapper(localName = "sayHello", targetNamespace = "http://ts.ch03/",
className = "hw3.SayHello")
@ResponseWrapper(localName = "sayHelloResponse", targetNamespace = "http://ts.ch03/",
className = "hw3.SayHelloResponse")
public Future<?> sayHelloAsync(
@WebParam(name = "name", targetNamespace = "")
String name,
@WebParam(name = "wh", targetNamespace = "")
String wh,
@WebParam(name = "asyncHandler", targetNamespace = "")
AsyncHandler<SayHelloResponse> asyncHandler);
/**
* @param wh
* @param name
* @param hf
*/
@WebMethod
@RequestWrapper(localName = "sayHello", targetNamespace = "http://ts.ch03/",
className = "hw3.SayHello")
@ResponseWrapper(localName = "sayHelloResponse", targetNamespace = "http://ts.ch03/",
className = "hw3.SayHelloResponse")
@Action(input = "http://ts.ch03/HelloWord/sayHelloRequest",
output = "http://ts.ch03/HelloWord/sayHelloResponse")
public void sayHello(
@WebParam(name = "name", targetNamespace = "")
String name,
@WebParam(name = "wh", targetNamespace = "", mode = WebParam.Mode.INOUT)
Holder<String> wh,
@WebParam(name = "hf", targetNamespace = "", mode = WebParam.Mode.OUT)
Holder<String> hf);
}
HelloWordImplService.java:
package hw3;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import javax.xml.ws.WebEndpoint;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceFeature;
/**
* This class was generated by the JAX-WS RI.
* JAX-WS RI 2.2.4-b01
* Generated source version: 2.2
*/
@WebServiceClient(name = "HelloWordImplService", targetNamespace = "http://ts.ch03/",
wsdlLocation = "http://localhost:7654/ts?wsdl")
public class HelloWordImplService extends Service {
private final static URL HELLOWORDIMPLSERVICE_WSDL_LOCATION;
private final static WebServiceException HELLOWORDIMPLSERVICE_EXCEPTION;
private final static QName HELLOWORDIMPLSERVICE_QNAME =
new QName("http://ts.ch03/", "HelloWordImplService");
static {
URL url = null;
WebServiceException e = null;
try {
url = new URL("http://localhost:7654/ts?wsdl");
} catch (MalformedURLException ex) {
e = new WebServiceException(ex);
}
HELLOWORDIMPLSERVICE_WSDL_LOCATION = url;
HELLOWORDIMPLSERVICE_EXCEPTION = e;
}
public HelloWordImplService() {
super(__getWsdlLocation(), HELLOWORDIMPLSERVICE_QNAME);
}
public HelloWordImplService(WebServiceFeature... features) {
super(__getWsdlLocation(), HELLOWORDIMPLSERVICE_QNAME, features);
}
public HelloWordImplService(URL wsdlLocation) {
super(wsdlLocation, HELLOWORDIMPLSERVICE_QNAME);
}
public HelloWordImplService(URL wsdlLocation, WebServiceFeature... features) {
super(wsdlLocation, HELLOWORDIMPLSERVICE_QNAME, features);
}
public HelloWordImplService(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public HelloWordImplService(URL wsdlLocation, QName serviceName,
WebServiceFeature... features) {
super(wsdlLocation, serviceName, features);
}
/**
* @return
* returns HelloWord
*/
@WebEndpoint(name = "HelloWordImplPort")
public HelloWord getHelloWordImplPort() {
return super.getPort(new QName("http://ts.ch03/", "HelloWordImplPort"),
HelloWord.class);
}
/**
* @param features
* A list of {@link javax.xml.ws.WebServiceFeature} to configure
* on the proxy. Supported features not in the <code>features</code> parameter
* will have their default values.
* @return
* returns HelloWord
*/
@WebEndpoint(name = "HelloWordImplPort")
public HelloWord getHelloWordImplPort(WebServiceFeature... features) {
return super.getPort(new QName("http://ts.ch03/", "HelloWordImplPort"),
HelloWord.class, features);
}
private static URL __getWsdlLocation() {
if (HELLOWORDIMPLSERVICE_EXCEPTION!= null) {
throw HELLOWORDIMPLSERVICE_EXCEPTION;
}
return HELLOWORDIMPLSERVICE_WSDL_LOCATION;
}
}
SayHello.java:
package hw3;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for sayHello complex type.
* <p>The following schema fragment specifies the expected content
* contained within this class.
* <pre>
* <complexType name="sayHello">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="name" type="{http://www.w3.org/2001/XMLSchema}string"
* minOccurs="0"/>
* <element name="wh" type="{http://www.w3.org/2001/XMLSchema}string"
* minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "sayHello", propOrder = {
"name",
"wh"
})
public class SayHello {
protected String name;
protected String wh;
/**
* Gets the value of the name property.
* @return
* possible object is
* {@link String }
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
* @param value
* allowed object is
* {@link String }
*/
public void setName(String value) {
this.name = value;
}
/**
* Gets the value of the wh property.
* @return
* possible object is
* {@link String }
*/
public String getWh() {
return wh;
}
/**
* Sets the value of the wh property.
* @param value
* allowed object is
* {@link String }
*/
public void setWh(String value) {
this.wh = value;
}
}
SayHelloResponse.java:
package hw3;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for sayHelloResponse complex type.
* <p>The following schema fragment specifies the expected content
* contained within this class.
* <pre>
* <complexType name="sayHelloResponse">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="wh" type="{http://www.w3.org/2001/XMLSchema}string"
* minOccurs="0"/>
* <element name="hf" type="{http://www.w3.org/2001/XMLSchema}string"
* minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "sayHelloResponse", propOrder = {
"wh",
"hf"
})
public class SayHelloResponse {
protected String wh;
protected String hf;
/**
* Gets the value of the wh property.
* @return
* possible object is
* {@link String }
*/
public String getWh() {
return wh;
}
/**
* Sets the value of the wh property.
* @param value
* allowed object is
* {@link String }
*/
public void setWh(String value) {
this.wh = value;
}
/**
* Gets the value of the hf property.
* @return
* possible object is
* {@link String }
*/
public String getHf() {
return hf;
}
/**
* Sets the value of the hf property.
* @param value
* allowed object is
* {@link String }
*/
public void setHf(String value) {
this.hf = value;
}
}
ObjectFactory.java与package-info.java略。
异步调用可以采用不同方式。第一种方式的客户端异步调用示例如下:
package hw3;
import java.util.concurrent.ExecutionException;
import hw3.HelloWord;
import hw3.HelloWordImplService;
import javax.xml.ws.Response;
public class HelloWordClient3 {
public static void main(String[] args) {
String name = "老师";
String wh = "你好";
HelloWordImplService service = new HelloWordImplService();
HelloWord port = service.getPort(HelloWord.class);
Response<SayHelloResponse> resp = port.sayHelloAsync(name, wh);
//响应是否完成
while(!resp.isDone()){
System.out.println("is not Done!");
}
try {
SayHelloResponse response = resp.get();
String hf1 = response.getHf();
String wh1 = response.getWh();
System.out.println(hf1 + "!" + wh1);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
这个示例是以轮询的方式(polling)实现异步调用。
第二个异步调用方式示例如下:
package hw3;
import java.util.concurrent.ExecutionException;
import javax.xml.ws.AsyncHandler;
import javax.xml.ws.Response;
public class HelloWordClient3 {
public static void main(String[] args) {
String name = "老师";
String wh = "你好";
HelloWordImplService service = new HelloWordImplService();
HelloWord port = service.getPort(HelloWord.class);
//这里使用了一个匿名内部类
port.sayHelloAsync(name, wh, new AsyncHandler<SayHelloResponse>(){
public void handleResponse(Response<SayHelloResponse> future){
try {
SayHelloResponse response = future.get();
String hf1 = response.getHf();
String wh1 = response.getWh();
System.out.println(hf1 + "!" + wh1);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
});
System.out.println("测试一下在之前还是在之后打印!!!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
这个示例是以回调的方式(callback)来演示异步调用的。由于此callback当请求发出去以后,当前的这个连接就会关闭,为了达到测试目的,加入 sleep,让客户端程序等待服务端的返回。注意,这个方法要传入一个javax.xml.ws.AsyncHandler类型的对象,所以这里我们定义了一个匿名内部类。当SOAP响应消息到达时,JAXWS会调用handleResponse这个方法来处理response。