前面我们使用过JaxRpcPortProxyFactoryBean和XFireClientFactoryBean来构建与web service交互的客户端。它们都将web service视为一个远程对象。现在我们来讨论一种消息驱动机制。采用这种机制,客户会发送XML消息给一个web service并接收返还的XML消息。Spring-WS提供了WebServiceTemplate来帮我们完成。
WebServiceTemplate是Spring-WS客户端API的核心。它使用Template设计模式提供了发送/接收消息的功能。为了说明WebServiceTemplate,我们创建几个PokerClient接口的不同实现,定义如下:
public interface PokerClient {
PokerHandType evaluateHand(Card[] cards) throws IOException;
}
每个实现都使用WebServiceTemplate以不同的方式来向poker hand evaluation web service发送消息。首先让我们在Spring中先配置WebServiceTemplate bean。
1. 使用web service template
如前所述,WebServiceTemplate是Spring-WS客户端API的核心。给web service发送消息包括创建SOAP信封和交互代码。这个过程对于每个web service客户都大同小异。如果发送消息给Spring-WS客户,你可能想让WebServiceTemplate来处理那些复杂的工作,这样你就可以关注于业务逻辑。在Spring中配置WebServiceTemplate非常简单,配置如下:
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.
WebServiceTemplate" >
<property name="messageFactory">
<bean class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory" />
</property>
<property name="messageSender" ref="messageSender" />
</bean>
WebServiceTemplate需要知道如何构造和发送消息。与messageFactory属性值绑定的对象负责处理构造消息的工作,该对象应该是一个Spring-WS的WebServiceMessageFactory接口的实现,Spring-WS提供了3个实现:AxiomSoapMessageFactory,DomPoxMessageFactory和SaajSoapMessageFactory。如果消息结构比较简单,可以考虑使用SaajSoapMessageFactory。如果要考虑性能,那么需要使用AxiomSoapMessageFactory。
messageSender属性指定了WebServiceMessageSender的一个实现。同样地,Spring-WS也提供了一些现成的实现:CommonsHttpMessageSender和HttpUrlConnectionMessageSender。如果你不需要使用CommonsHttpMessageSender提供的诸如HTTP身份认证的功能,那么使用HttpUrlConnectionMessageSender就足够了,但是如果你需要使用这些功能,你就必须使用CommonsHttpMessageSender,而且你还需要添加Jakarta Commons HTTP到你的classpath中。本例中,我们选择使用HttpUrlConnectionMessageSender,配置如下:
<bean id="messageSender" class="org.springframework.ws.transport.http.
HttpUrlConnectionMessageSender" >
<property name="url" value="http://localhost:8080/Poker-WS/services" />
</bean>
url属性指定了服务的地址。值得注意的是它将匹配WSDL中的URL。如果你想要使用CommonsHttpMessageSender,只需要简单地替换掉class属性值即可。
发送消息
一旦配置过WebServiceTemplate之后,我们就可以使用它来发送和接收消息。WebServiceTemplate提供了一些方法用于发送和接收事件。sendAndReceive是最常用的一个:
public Boolean sendAndReceive(Source requestPayload, Result responseResult) throws IOException
sendAndReceive方法接收两个参数。Source对象表示发送给web service的消息的payload,Result对象表示从web service返回的消息的payload。Source和Result都是Java XML API的标准接口,它们都有很多种实现,这里选择的是JDOM。
在客户端使用marshaler
除了sendAndReceive方法,WebServiceTemplate还提供了marshalSendAndReceive方法负责发送和接收由Java对象转化或将要转化为Java对象的XML消息。使用marshalSendAndReceive方法只需要传递一个Request对象,它会返回一个Response对象。本例中,输入对象为EvaluateHandRequest,输出对象为EvaluateHandResponse。
但是,WebServiceTemplate怎么知道如何转化EvaluateHandRequest和EvaluateHandResponse对象呢?其实,它并不知道如何转化。它只是绑定了一个marshaler和一个unmarshaler,配置如下:
<bean id="webServiceTemplate"
class="org.springframework.ws.client.core.WebServiceTemplate">
<property name="messageFactory">
<bean class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
</property>
<property name="messageSender" ref="urlMessageSender" />
<property name="marshaller" ref="marshaller" />
<property name="unmarshaller" ref="marshaller" />
</bean>
这里我们在指定了一个marshaller和一个unmarshaller,它们都引用了一个marshaller bean。
2. 使用web service gateway
Spring数据访问API包含一些提供模板功能的支持类,而模板本身是不需要被配置的。同样地,Spring-WS提供了WebServiceGatewaySupport。它能自动地提供一个WebServiceTemplate给继承它的客户端类。