构建异步服务的工具假使存在有异步服务的需求,那么有什么工具帮助我们来构建这些服务呢——以及构建异步服务的客户端?
绝大多数编程模型和框架都很好地提供了编写同步服务的客户端的工具。对于编写同步服务也是如此。同步的“调用-返回”模型是用绝大多数编程语言编写代码的标准形式。结果是,编写同步服务或同步服务客户端通常不用对标准的编程模型进行多少扩展。例如,在Java中,这通常意味着一个服务被实现为一个类中的一个方法,而这个服务的客户端就是对这个类方法的调用。
编写异步服务和异步服务客户端的工具并没有得到很好的发展。Java是众多编程语言的典型,异步编程在其中成为一等公民还是最近的事情——随着在Java 5中并发类的出现。
还有些异步处理工具可以通过一些协议相关的编程模型[
2]来使用。举个例子,JAX-WS [
5]提供了编写同步服务的异步客户端的方法,使用Web服务作为客户端和服务间的通信方法。
这种情况中,假设同步服务调用的客户端代码如下: this:
OrderResponse placeOrder( OrderRequest oRequest );
例 1:简单的同步placeOrder操作等价的异步服务调用如下:
Future placeOrderAsync( OrderRequest oRequest,
AsyncHandler responseHandler );
例 2:placeOrder请求的异步形式对调用的异步响应经由声明如下的异步响应处理程序发回给客户端:
class OrderResponseHandler implements AsyncHandler {
public void handleResponse( Response theResponse ){
OrderResponse orderResponse = theResponse.get();
}
}
例 3:在placeOrder完成之后处理程序方法会被调用JAX_WS不支持编写异步服务。它也只支持一个特定请求刚好一个响应的情况。
一个支持异步风格客户端
和异步服务的Java框架是JMS API [
6]。当客户端和服务之间使用支持JMS的消息系统进行通信时就可以使用JMS API。在Java EE框架中,可以通过消息驱动Bean[
7]使用JMS。尽管JMS方法支持一些异步服务,但是JMS将客户端和服务代码束缚到了某些消息基础设施的使用之上。
最后,支持所能想到的异步业务过程的一个整体语言都已以被开发出来了。这就是业务过程执行语言(简称BPEL)[
8]。BPEL特别擅长协调一组服务,包括同步的和异步的,但是它可能不擅长编写涉及大量数据操纵的服务或客户端。
SCA和异步服务SCA对创建异步服务和异步服务客户端提供了直接支持。SCA支持具有简单的交互模式(每个请求消息一个响应消息)的异步服务,也支持具有更复杂的交互模式(每个请求0个、1个或多个响应消息)的异步服务——记住,我们的“简单”订书过程为每条订书请求产生两条响应消息。
SCA支持使用一个范围广泛的编程语言中的任何一种编写的异步服务,例如包括Java和BPEL。此外,SCA还能够选择客户端和提供者间的通信方法——它可能使用消息基础设施(如JMS所使用的),但它也可能选择使用Web服务基础设施。SCA不会把客户端或服务提供者代码束缚到任何特殊的通信基础设施上。
SCA使用以下概念给服务客户端和服务提供者之间的通信建模:
- 服务,包含在一个接口内的一个或多个操作的集合,服务提供者实现这个接口。
- 引用,客户端使用它调用服务提供者的操作。引用一般是一个代理对象,它实现了服务提供者实现的相同接口。
在同步服务情况中,接口的每个操作有一个“调用-返回”风格,其中消息作为操作的参数被发送给服务提供者,响应则是操作的返回值:
OrderResponse placeOrder( OrderRequest oRequest );
例 4:简单的同步placeOrder操作对于异步服务,SCA有一个
回调(callback)概念。一个回调暗示了通信是双向且异步的。客户端通过服务提供者上的操作调用提供者——提供者相关的响应使用一个单独的
服务回调接口回调客户端。尽管服务提供者实现了服务接口,但是
客户端必须实现回调接口。
在例 4中显示的同步操作的等价异步回调包含如下一个请求操作:
void placeOrder( OrderRequest oRequest );
例 5:异步placeOrder服务请求……结合如下的回调接口中的一个操作:
void placeOrderResponse( OrderReponse oResponse );
例 6:placeOrder响应的回调操作SCA方式的异步服务的一个重要方面就是:在初始客户端调用服务提供者之后,服务提供者可以通过回调接口在任意时间回调客户端。服务提供者可以使用定义在回调接口中的任何操作,在对来自客户端单个请求的响应中,提供者
可能调用回调接口中一个或多个或零个的操作。最简单的情形是让提供者对于每个由客户端所调用的服务操作只调用回调接口中的一个操作。