创建异步的客户端

前面博客中,我们通过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>
 * &lt;complexType name="sayHello">
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="name" type="{http://www.w3.org/2001/XMLSchema}string"
 *                minOccurs="0"/>
 *         &lt;element name="wh" type="{http://www.w3.org/2001/XMLSchema}string"
 *                minOccurs="0"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/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>
 * &lt;complexType name="sayHelloResponse">
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element name="wh" type="{http://www.w3.org/2001/XMLSchema}string" 
 *                minOccurs="0"/>
 *         &lt;element name="hf" type="{http://www.w3.org/2001/XMLSchema}string" 
 *                minOccurs="0"/>
 *       &lt;/sequence>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/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。


你可能感兴趣的:(java-web服务)