该部分将为高级用户介绍复杂但是更加强大的基于XML的WebService客户端,然而如果你是一个新手还是建议你使用axis的代码生成器进行客户端的开发.
Web services能够用于为用户提供广泛的功能从单一的功能到像获取证券报价这样的实时操作以及耗时的商业服务.当我们利用这些服务的时候我们单一的客户 端操作方式将不会适合所有的复杂的服务操作 . 例如:我们使用单个传输通道(比如HTTP协议)来执行一个IN-OUT(有输入也有输出)类型并且需要很多时间执行的web service的时候,我们经常会受到"connection time outs"(连接超时). 更多的,我们的一个客户端需要同时处理多个服务执行请求,如果我们使用"blocking"(阻塞方式)方式的客户端API将会客户端应用程序的性能. 同样的,there are various other consequences such as One-Way transports that come into play when we need them. 让我们来分析一下通常的服务范例.
很多的WebService引擎给用户提供了阻塞(Blocking)和非阻塞(Non-Blocking)的客户端API.
-
Blocking API 阻塞式API- 一旦服务请求发送后,客户端应用程序将阻塞,只有在客户端收到响应或者错误信息程序才会恢复运行,这是执行Web Service最简单的方式,在很多情况下它也适合业务.
-
Non-Blocking API 非阻塞式API- 这是一个基于回调函数或者池技术的API. 一旦一个服务请求发出后客户端将立即恢复运行不会阻塞,服务的响应将会由回调函数来处理. 这将允许客户端同时执行多个Web Service请求而不需要等待前一个请求的响应.
以上的机制都是工作在API层次的. 我们把这种使用在非阻塞API上的异步行为叫做API层异步.
以上的机制都使用单一的连接去发送请求和接收响应.这都明显在性能上落后于使用两条连接(单向或双向)进行进行请求和响应的传输 . 因此以上的机制都不能解决长时间运行的交易,连接将在操作还没完成就会超时. 一种解决方案是使用分开的两条传输连接来传输请求和响应 . 我们叫这种方案为 传输层异步.
通过API层异步和传输层异步,我们能获得下表中四种不同的Web Service调用模式.
API (Blocking/Non-Blocking) |
双路传输 (Yes/No) |
描述 |
阻塞 |
No |
最简单和熟悉的调用模式 |
非阻塞 |
No |
使用回调函数或池 |
阻塞 |
Yes |
这在服务操作是一般的请求响应而传输方式使用单向方式(例如. SMTP协议) |
非阻塞 |
Yes |
获得最多的异步行为,在API层和传输层同时实现异步 |
Axis2 为用户提供以上方式来调用Web services.
以下部分将用ServiceClient
实现以上的多种调用模式来调用一个Web Service. 所有代码都保持在 "samplesuserguidesrc" 目录.
这部分提供四种的客户端.
- 发送请求返回响应并且阻塞的客户端
- 单向传输,非阻塞的客户端
- 发送请求返回响应,非阻塞,使用一条连接传输
- 发送请求返回响应,使用二条连接传输
发送请求返回响应并且阻塞的客户端
以下代码执行MyService服务的echo操作使用阻塞和单通道调用.
try {
OMElement payload = ClientUtil.getEchoOMElement();
Options options = new Options();
options.setTo(targetEPR); // this sets the location of MyService service
ServiceClient serviceClient = new ServiceClient();
serviceClient.setOptions(options);
OMElement result = serviceClient.sendReceive(payload);
System.out.println(result);
} catch (AxisFault axisFault) {
axisFault.printStackTrace();
}
}
绿色高亮代码是对服务的调用.
测试客户端,使用 "Axis2_HOME/samples/userguide" 目录下的ant脚步. 运行"run.client.blocking"任务.如果看见打印出来的的响应包就是正常的.
单向传输,非阻塞的客户端
调用 "MyService"种的只有输入的 操作"ping" (查看 创建Web Service服务). 以下是代码:
try {
OMElement payload = ClientUtil.getPingOMElement();
Options options = new Options();
options.setTo(targetEPR);
ServiceClient serviceClient = new ServiceClient();
serviceClient.setOptions(options);
serviceClient.fireAndForget(payload);
/**
* We need to wait some time for the message to be sent. Otherwise,* if we immediately exit this function using the main thread,* the request won't be sent.
*/
Thread.sleep(500);
} catch (AxisFault axisFault) {
axisFault.printStackTrace();
}
我们调用一个只有输入的调用 ,在客户端使用 fireAndForget()
调用这个服务. 这样将不会阻塞而会立即返回 测试运行 "run.client.ping" 任务 ,Axis2Home/samples/userguide".
发送请求返回响应,使用一条连接传输
在 "EchoBlockingClient"中一旦serviceClient.sendReceive(payload)被调用
,客户阻塞直道操作完成. 这样的情况在一个客户应用或者GUI中调用多个WebService时将会不令人满意.一种解决方法是使用非阻塞API来调用Web Service. Axis2 提供给用户一个基于回调函数的API.
一个简单的客户端EchoNonBlockingClient保存在 "Axis2_HOME/samples/userguide/src/userguide/clients".
serviceClient.sendReceiveNonblocking(payload,callback);
这个调用接受一个 回调 对象作为参数, Axis2 客户端API提供一个抽象的回调类它有以下方法:
public abstract void onComplete(AsyncResult result);
public abstract void onError(Exception e);
public boolean isComplete() {}
开发人员需要在子类覆盖 onComplete() 和 onError() 方法. Axis2引擎在WebService响应被接收后就执行onComplete()方法. 这样就WebService调用就不会阻塞.
发送请求返回响应,使用二条连接传输
这个解决方案在调用Web Service时候使用前面的非阻塞API有一个限制.这个限制是因为使用一个连接调用Web Service和接收响应. 换句话说,客户端API为开发者提供非阻塞机制,但是像HTTP这样的双向传输方式任然会在同一连接上传输请求和相应 . 长时间运行的Web Service 或者使用单向传输的例如SMTP协议不能简单的使用非阻塞API.
最简单的解决方案是使用分离的传输连接 (单向或者双向) 传输请求和响应. 接下来需要解决另外一个问题,然而,随后是如何将请求和响应进行关联. WS-Addressing 提供一个很好的方法是利用 <wsa:MessageID>和 <wsa:RelatesTo> 头. Axis2提供在两条传输线路上客户端API上基于地址的关联机制. (TAxis2和姓不依赖于 WS-Addressing,但是包含一组参数,like in addressing,that can be populated by any method. WS-Addressing is one of the uses that may populate them. Even the transports can populate them. Hence,Axis2 has the flexibility to use different addressing standards.)
用户能在两条线路中通过设置标志 阻塞 和非阻塞 API 间选择进行选择,同样的API可以使用2条不同的传输连接去执行WebService. . 超级异步!! (PS:貌似不很超级)
try {
OMElement payload = ClientUtil.getEchoOMElement();
Options options = new Options();
options.setTo(targetEPR);
options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
options.setUseSeparateListener(true);
options.setAction("urn:echo"); // this is the action mapping we put within the service.xml
//Callback to handle the response
Callback callback = new Callback() {
public void onComplete(AsyncResult result) {
System.out.println(result.getResponseEnvelope());
}
public void onError(Exception e) {
e.printStackTrace();
}
};
//Non-Blocking Invocation
sender = new ServiceClient();
sender.engageModule(new QName(Constants.MODULE_ADDRESSING));
sender.setOptions(options);
sender.sendReceiveNonBlocking(payload,callback);
//Wait till the callback receives the response.
while (!callback.isComplete()) {
Thread.sleep(1000);
}
} catch (AxisFault axisFault) {
axisFault.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
//Close the Client Side Listener.
sender.cleanup();
} catch (AxisFault axisFault) {
//have to ignore this
}
}
ptions.setUseSeparateListener(true)方法告知
Axis2 引擎使用2条独立的连接分别传输请求和响应. 最好 sender.cleanup()
告知 Axis2 引擎停止客户端监听,开始接收响应.