`
hacker_zxf
  • 浏览: 143346 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

在Spring中使用XFire构建Web Service应用

阅读更多
轉自: 开发者在线 Builder.com.cn
原: http://www.builder.com.cn/2007/0522/402440.shtml

概述

XFire是与Axis 2并列的新一代Web Service框架,通过提供简单的API支持Web Service各项标准协议,帮助你方便快速地开发Web Service应用。XFixe内建在STAX的基础上之上,STAX是基于流的XML解析引擎,这使得XFire拥有很高的性能。

相对Axis来说,目前它的人气指数相当高,加上其提供了和String集成的支持,在目前的Web Service开源社区拥有众多的追随者,XFire被多个开源项目所使用。XFire为Spring提供了支持,这使得我们可以很容易在Spring中使用XFire构建Web Service应用。本文讲述了如何使用XFire在Spring中开发Web Service的具体过程。

XFire特性

XFire是Web Service框架的后起之秀,它从现有的框架中借鉴了许多优秀的理念,力争将Web Service的应用开发难度降到最低。此外,还提供了各种绑定技术、支持多种传输协议,对Web Service体系中许多新的规范提供了支持。简单来说,它具有以下一些特性:

支持重要的Web Service规范,如SOAP、WSDL、WS-I Basic Profile,、WS-Addressing、WS-Security等;
高性能的SOAP 栈设计;
可插拔的绑定,支持POJO、XMLBeans、JAXB1.1、JAXB2以及Castor;
支持JSR 181规范,该规范通过JDK 5.0注解将POJO导出为Web Service;
支持多种传输协议:HTTP、JMS、XMPP、In-JVM等,其中In-JVM允许我们在不启动Web应用器的情况下,象一般的程序一样测试Web Service应用;
易用的API,XFire API简洁明了,便于使用;
支持Spring、Pico、Plexus、Loom等容器;
支持JBI(Java Business Integration:Java 业务整合)规范,JBI是JSR 208的实现;
能够根据WSDL创建客户端和服务器端的存根代码;
率先对JAX-WS提供了支持,JAX-WS是JAX-RPC的替代者。
XFire 体系及重要API

ServiceFactory
ServiceFactory是XFire的核心类,它可以将一个POJO生成为一个Web Service。让我们通过一个最简单的例子了解ServiceFactory的用途,假设我们在一个POJO中定义了一个业务,现在希望将其导出为Web Service,通过ServiceFactory可以轻而易举地达到目的:

XFire xfire = XFireFactory.newInstance().getXFire();

ServiceFactory factory = new ObjectServiceFactory(xfire.getTransportManager(), null);

Service service = factory.create(YourService.class);

这样我们就为YourService类创建基于SOAP 1.1封装的Web Service。Service的输入输出参数如果为简单类型的对象(由String、int、long等基本类型组成),无须进行额外的映射设置,对于复杂类型的输入输出Service,XFire将会自动尝试将其序列化(通过Aegis绑定)。紧接着,你就可以注册这个Service。

xfire.getServiceRegistry().register(service);

XFire推荐通过一个接口开放服务,此时,你可以指定一个具体的实现类:

service.setProperty(ObjectInvoker.SERVICE_IMPL_CLASS, YourServiceImpl.class);

Handler
一个Handler可以看成是XFire的一个加工套件,XFire通过它们定义SOAP发送和接收之前的各种加工处理逻辑。如Handler可以对SOAP体的内容进行加工处理,或者SOAP头进行处理。可以简单地通过扩展AbstractHandler定义一个自己的Handler类:

import org.codehaus.xfire.MessageContext;

import org.codehaus.xfire.handler.AbstractHandler;

public class YourHandler extends AbstractHandler

{

public void invoke(MessageContext context)

{

// Do Sth...

}

}

Handler可以注册到Service或Transport(代表SOAP输入输出的的传输对象)中,在服务请求和响应管道里,Service和Transport注册的Handler将执行额外的处理操作。你可以按如下方式注册Handler:



Servic s = factory.create(YourService.class);

s.addInHandler(new YourHandler1());①添加一个Handler,对输入SOAP进行处理

s.addOutHandler(new YourHandler2());②添加一个Handler,对输出SOAP进行处理

s.addFaultHandler(new YourHandler3());③添加一个Handler,对错误SOAP进行处理



下面的Handler对SOAP头进行处理,添加一些特定的信息:

import org.codehaus.xfire.MessageContext;

import org.codehaus.xfire.handler.AbstractHandler;

public class YourHandler extends AbstractHandler

{



public QName[] getUnderstoodHeaders()

{

return new QName[] { new QName("YourHeader", "urn:your:header:ns") };

}

}


在管道中以流方式处理SOAP
XFire是完全基于流数据处理进行工作的系统,这意味着XFire不是将整个SOAP文档缓存在内存中,而是以管道的方式接收SOAP流数据。这种工作方式的转变带来了可观的性能回报,同时节省了内存的占用。

对于习惯了Axis、GLUE等这些基于DOM处理模型Web Service框架的开发者来说,需要一些时间来适应这种转变。

XFire从管道中接收一个SOAP请求到返回一个SOAP响应,会经历一系列的阶段。在管道调用的任何一个阶段,XFire都可以添加一些额外的Handler,在对消息进行加工处理后再传入到下一个阶段中。图1展示了XFire管道从接收SOAP请求到返回SOAP响应所经历的所有阶段:




图1 XFire Web Service请求和响应的过程

在SOAP请求消息对Web Service发起真正调用之前,分别会经过传输(Transport)、预转发(PreDispatch)、转发(Dispatch)、策略实施(Policy)、用户信息处理(User)、预调用(PreInvoke)、服务调用(Service Invocation)等阶段。当,Web Service调用后,XFire生成响应SOAP消息并通过管道发送给客户端请求者,这一过程会先后经历调用后(PostInvoke)、用户信息处理(User)、策略实施(Policy)、传输(Transport)这四个阶段。每一个阶段都是一个可控点,通过编写并注册一些相应的Handler就可以实施一些额外处理逻辑,如审计、SOAP消息加密、签名、压缩等。

将POJO Bean导出为Web Service

通过XFire为Spring提供的服务导出器可以轻松地将POJO导出为标准的Web Service,此外,XFire还允许我们使用JSR 181注解对POJO进行标注,无需使用XML配置就可以导出为Web Service,各种复杂的转换细节被巧妙地隐藏在XFire之中。

使用导出器导出Web Service

XFire为Spring提供了方便易用的导出器XFireExporter,借助XFireExporter的支持,我们可以在Spring容器中将一个POJO导出为Web Service。BbtForum是Baobaotao论坛业务服务类,它拥有众多的业务方法,我们现在希望将其提供查询最近几天精华帖子数的业务方法开放为Web Service。为了避免过多地开放不必要的接口方法,需要定义了一个BbtForumService窄接口,它定义那些需要开放为Web Service的业务方法:

package com.baobaotao.xfire.server;

public interface BbtForumService {

int getRefinedTopicCount(int lastDay);①查询最近几天论坛精华帖子数的服务接口

}

将一个业务类所有需要开放为Web Service的方法通过一个窄接口来描述是值得推荐的作法,这让Web Service的接口显得很“干净”。其次,XFire的导出器也需要服务接口的支持,因为它采用基于接口的动态代理技术。真实的业务类当然需要实现Web Service窄接口:

package com.baobaotao.service;

import javax.jws.WebService;

import com.baobaotao.xfire.server.BbtForumService;

public class BbtForum implements BbtForumService{①实现Web Service窄接口

public int getRefinedTopicCount(int lastDay) {②该方法在窄接口中定义,导出为Web Service服务

if(lastDay <= 2) return 10;

else if(lastDay <= 5) return 20;

else return 32;

}



}

BbtForum中的方法在真实的系统中应该引用其它的业务类或DAO获取数据库中的真实数据,为了简化实例,我们通过一段简单的代码进行模拟,如②所示。

在拥有了窄接口之后中,剩余的工作就是在Spring配置文件中通过XFireExporter将BbtForum#getRefinedTopicCount()方法导出为Web Service,具体配置如代码清单1所示:

代码清单1 applicationContext.xml:将POJO导出Web Service

<beans>

①引入XFire预配置信息

<import resource="classpath:org/codehaus/xfire/spring/xfire.xml" />

②使用XFire导出器

<bean id="BbtForumService" class="org.codehaus.xfire.spring.remoting.XFireExporter">

<property name="serviceFactory" ref="xfire.serviceFactory" />②-1:引用xfire.xml中定义工厂

<property name="xfire" ref="xfire" />②-2:引用xfire.xml中定义的xfire实例

<property name="serviceBean" ref="bbtForum" />②-3:业务服务Bean

<property name="serviceClass"②-4:业务服务Bean的窄接口类

value="com.baobaotao.xfire.server.BbtForumService" />

<property name="name" value="BbtForumServiceUT"/>②-5:Web Service名称

</bean>

<bean id="bbtForum" class="com.baobaotao.service.BbtForum" />

</beans>

上面的配置将BbtForum所有定义在BbtForumService窄接口中的方法导出为Web Service。在XFire核心JAR包中拥有一个预定义的Spring配置文件,它定义了XFire在Spring中必须用到的一些Bean和资源,需要引入这个预定义的配置文件,如①所示。紧接着,就可以使用XFireExporter将业务类导出为Web Service了。②-1、②-2为导出器引入XFire环境,对于任何导出器,这都是标准的配置,所以如果有多个导出器,可以将这两个属性通过一个父<bean>标签进行抽象。而②-3、②-4分别定义了业务服务类及需要导出为Web Service方法的窄接口。Web Service的默认名称是窄接口的类名,即BbtForumService,你可以通过name属性显式指定Web Service的名称,如②-5所示。

通过这个简单的配置,就完成了将业务服务类开放为Web Service的工作,接下来,我们就可以通过配置Web 服务器的web.xml,将其通过HTTP传输协议开放出去。

配置web.xml

一般情况下,我们通过HTTP作为Web Service的传输协议,这样你只需启动一个Web服务器(如Tomcat),客户端就可以通过HTTP访问到Web Service服务了。为了集成Spring容器,XFire专门提供一个XFireSpringServlet,我们可以在web.xml中配置该Servlet,将Spring容器中定义的Web Service在某个URI下发布,如代码清单2所示:

代码清单2 web.xml配置

<web-app>

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>classpath:applicationContext.xml</param-value>①刚才配置的Spring文件

</context-param>

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

</listener>

<servlet>②配合Spring容器中XFire一起工作的Servlet

<servlet-name>xfireServlet</servlet-name>

<servlet-class>org.codehaus.xfire.spring.XFireSpringServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>xfireServlet</servlet-name>

<url-pattern>/service/*</url-pattern>③在这个URI下开放Web Service服务

</servlet-mapping>

</web-app>

首先,我们指定在代码清单1中所配置的Spring配置文件,如①所示。然后定义一个XFireSpringServlet,让其截取所有/service URI下的请求,如②和③所示。

创建一个Tomcat配置文件baobaotao.xml,并编写一行映射配置(这里使用Tomcat 5.5),这种方式无须将Web应用打包成WAR,方便开发测试:

<Context path="/baobaotao" docBase="D:/masterSpring/chapter16/webapp"/>

将baobaotao.xml放置到<TOMCAT_HOME>/conf/Catalina/localhost目录下,启动Tomcat服务,键入http://localhost:8080/baobaotao/service/BbtForumService?wsdl,你将可以看到BbtForumService对应的WSDL,如图2所示:



图2 BbtForumService的WSDL

阅读这个WSDL文档,我们可以知道BbtForum的getRefinedTopicCount已经被成功地发布为Web Service了。只要拿到这个WSDL就可以开发相应的客户端调用程序了。

使用JSR 181注解导出Web Service

前面两小节中,我们领教了XFireExporter导出器的威力。在需要导出为Web Service的业务类数目不大时,XFireExporter的配置方式非常优雅。但是,如果有很多需要导出为Web Service的业务类,你必须分别为它们配置一个XFireExporter,这让我们回忆起了TransactionProxyFactoryBean(每一个需要事务功能的业务类需要分别配置)。在学习过@Transaction注解后,我们自然而然地希望使用类似注解技术完成Web Service导出的工作。

JSR 181就是为此目的而提出的,它是BEA领导的一个Web Service规范。XFire已经支持JSR 181 2.0,你既可以使用JDK 5.0的注解,也可以在JDK 5.0之前的版本中使用commons-attributes注解。

使用JSR 181的明显好处是,你仅需在业务类和窄接口标注JSR 181注解,不管你有多少需要导出为Web Service的业务类,仅须在Spring中配置一个XFire提供的JSR 181注解增强Bean就可以了。

注解增强处理器会对Spring容器中所有标注JSR 181注解的业务类进行处理,并分别将它们导出为Web Service。使用JSR 181时,必须将XFire的依赖类库xfire-jsr181-api-1.0-M1.jar添加到类路径中。

如果输入、输出的对象类型仅包括基本类型的属性,仅需要在业务类和窄接口中分别使用@WebService注解进行简单的配置就可以了,XFire将根据默认约定导出Web Service。

窄接口仅需要定义一个@WebService注解,并指定SOAP的命名空间就可以了:

package com.baobaotao.xfire.server;

import javax.jws.WebService;

@WebService(targetNamespace = "http://www.baobaotao.com")①指定SOAP的命名空间

public interface BbtForumService {

int getRefinedTopicCount(int lastDay);

}

XFire应用JSR 181比较怪的一点是,除了需要在窄接口中提供注解外,在实现业务类中也需要提供相应的注解:

package com.baobaotao.service;

import javax.jws.WebService;

import com.baobaotao.xfire.server.BbtForumService;

@WebService(serviceName = "BbtForumService",①指定导出的Web Service名称

endpointInterface = "com.baobaotao.xfire.server.BbtForumService")②对应的窄接口

public class BbtForum implements BbtForumService{



}

如果碰到以下应用场景:输入、输出对象是复杂的对象(如未使用泛型的集合类),当返回类型是一个对象但不希望输出所有的结果,或者不希望使用默认的属性名。

这时可以在业务方法中通过@WebMethod、@WebResult等注解提供额外的信息来达到目的。更多关于JSR 181的信息请参考:http://dev2dev.bea.com/webservices/jwsm.html。

按照相似的方式,可以为应用中其它的业务类进行Web Service标注,在完成标注后,需要在Spring配置中启用XFire JSR 181处理器,对Spring容器中所有标注@WebService的Bean进行统一的处理,以便执行真正Web Service的导出工作。XFire在Spring中对应的配置如下所示:

代码清单3 applicationContext.xml:使用JSR 181导出Web Service

<beans >

<import resource="classpath:org/codehaus/xfire/spring/xfire.xml" />

<bean id="webAnnotations"①该Bean获取Spring容器中所有标注@WebService的Bean

class="org.codehaus.xfire.annotations.jsr181.Jsr181WebAnnotations" />

<bean id="jsr181HandlerMapping"②对标注@WebService的Bean进行处理,完成导出工作

class="org.codehaus.xfire.spring.remoting.Jsr181HandlerMapping">

<property name="xfire" ref="xfire" />

<property name="webAnnotations" ref="webAnnotations" />

</bean>

③该Bean标注了@WebService注解

<bean id="bbtForum" class="com.baobaotao.service.BbtForum" />

</beans>

重启Tomcat,查看http://localhost:8080/baobaotao/service/BbtForumService?wsdl,你依旧可以看到如图2 BbtForumService的WSDL所示的WSDL。

各种客户端调用方式

XFire为访问服务端Web Service提供了各种方便的方式:在可以获取服务端窄接口类的情况下,可以根据服务地址和窄接口类创建客户调用程序。

如果不能获得服务窄接口类,XFire允许你通过WSDL文件生成客户端调用程序,通过指定服务接口的方式调用服务。鉴于这种调用方式不够面向对象,XFire提供了一个根据WSDL生成客户端存根代码的工具,这样你就可以方便以面向对象的方式编写客户端程序了。

使用服务端的窄接口类

如果客户端可以获取服务端的Web Service的窄接口类,这时可以使用XFire的ObjectServiceFactory将对应地址的Web Service转换为窄接口实例进行调用,如代码清单4所示:

代码清单4使用窄接口调用Web Service应用

package com.baobaotao.xfire.client;

import org.codehaus.xfire.client.XFireProxyFactory;

import org.codehaus.xfire.service.Service;

import org.codehaus.xfire.service.binding.ObjectServiceFactory;

import com.baobaotao.xfire.server.BbtForumService;

public class WithClassClient {

public int getRefinedTopicCount() {

①根据窄接口创建Service模型

Service serviceModel = new ObjectServiceFactory().create(BbtForumService.class);

②服务对应URL地址

String serviceURL = "http://localhost:8080/baobaotao/service/BbtForumService";

BbtForumService service = null;

try {

③将Web Service转换为窄接口实例

service = (BbtForumService) new XFireProxyFactory().

create(serviceModel, serviceURL);

} catch (Exception e) {

throw new RuntimeException(e);

}

return service.getRefinedTopicCount(20);④调用Web Service方法

}

public static void main(String[] args) {

WithClassClient client = new WithClassClient();

System.out.println("topic count is:"+client.getRefinedTopicCount());

}

}

XFire根据Service模型对象及Web Service的URL地址就可以构造出Web Service的调用实例。在服务端Tomcat启动的情况下,运行以上的客户端代码,将可以获得正确的输出。

使用WSDL文件构造客户端程序

并不是任何时候都可以获得Web Service服务端的窄接口类,但我们必然可以获取Web Service对应的WSDL文档。XFire允许我们仅通过Web Service对应的WSDL文件构造客户端访问程序。

这无疑给创建客户端程序带来了极大的便利性,你可以直接通过URL指定WSDL,也可以将WSDL保存在本地系统中,通过InputStream的方式获取WSDL内容。下面,我们使用InputStream的方式提供WSDL:

代码清单5通过WSDL创建客户端程序

package com.baobaotao.xfire.client;

import java.net.URL;

import org.codehaus.xfire.client.Client;

public class OnlyWsdlClient {

public int getRefinedTopicCount() {

try {

String wsdl = "com/baobaotao/xfire/client/BbtForumService.wsdl";①对应的WSDL文件

Resource resource = new ClassPathResource(wsdl);

Client client = new Client(resource.getInputStream(), null);②根据WSDL创建客户实例

③调用特定的Web Service方法

Object[] results = client.invoke("getRefinedTopicCount",new Object[]);

return (Integer) results[0];

} catch (Exception e) {

throw new RuntimeException(e);

}

}

public static void main(String[] args) {

OnlyWsdlClient client = new OnlyWsdlClient();

System.out.println("topic count is:" + client.getRefinedTopicCount());

}

}

你可以通过http://localhost:8080/baobaotao/service/BbtForumService?wsdl地址获取BbtForumService对应的WSDL,并将其保存在工程项目的src对应的类包目录:com/baobaotao/xfire/client/BbtForumService.wsdl。

我们通过Spring的ClassPathResource读取BbtForumService.wsdl,XFire从Resource中获取WSDL的输入流并生成一个客户端实例。接着,我们就可以通过这个客户端实例,指定Service服务名和输入参数调用Web Service的服务方法了,如③所示。

可能会有读者认为这种完全根据WSDL创建客户端程序的方式会带来低劣的运行性能,笔者通过测试发现,确实会造成一定的性能降低,但也不象想象中那样低效。

使用基于窄接口的客户端程序和使用基于WSDL的客户端程序访问一次BbtForumService的时间依次是1300 ms和1450 ms。如果WSDL文档很复杂,由于需要解析整个WSDL文档,这种客户端程序的性能会受到更多的挑战。不过,如果只要在程序中缓存Client实例,由于创建Client的代价是一次性的,性能问题就可以忽略了。

根据WSDL生成客户端代码

XFire允许通过运行Ant任务,根据WSDL文件生成访问Web Service的客户端代码存根,同时XFire还提供了一个Eclipse插件完成相同的任务。本节里,我们将学习通过XFire Eclipse插件生成BbtForumService客户端存根代码的知识。

安装Eclipse XFire 插件

1.Help->Software Updates->Find and Install...

2.选择“Search for new features to install”,并点击Next;

3.选择“New Remote Site...”,创建一个Name为XFire,URL为

http://dist.codehaus.org/xfire/update/的网站;

4.点击Finish安装XFire插件。


使用插件创建客户端代码存根
File->New->Other...->XFire->Code generation from WSDL document;
弹出一个对话框,如图3所示:


图3创建客户端代码存根

指定WSDL文件的位置,存根代码的输出地址及对应的类包,点击Finish。

XFire插件将在生成客户端代码存根的同时生成服务端代码的存根,如下图所示:


图4生成的代码

BbtForumServiceClient是BbtForumServicePortType的工厂类,它提供了若干个获取BbtForumServicePortType实例的重载方法。BbtForumServicePortType对应服务端的窄接口BbtForumService类。而BbtForumServiceImpl是服务端的存根代码,在META-INF中还有XFire的服务配置文件。对于客户端来说,一般不需要服务端的代码,所以你可以将BbtForumServiceImpl和META-INF删除。

下面,我们利用XFire生成的BbtForumServiceClient对服务端的Web Service进行调用:

package com.baobaotao.xfire.client;

public class StubClient {

public static void main(String[] args) {

BbtForumServiceClient client = new BbtForumServiceClient();

String serviceUrl = "http://localhost:8080/baobaotao/service/BbtForumService";

①获取对应服务窄接口实例

BbtForumServicePortType portType = client.getBbtForumServiceHttpPort(serviceUrl);

int count = portType.getRefinedTopicCount(20);②对服务进行调用

System.out.println("count:" + count);

}

}

我们首先实例化一个BbtForumServiceClient,然后通过URL指定Web Service的服务地址,然后创建一个服务的窄接口实例,如①所示,接着我们就可以使用这个窄接口实例进行Web Service服务的调用了。

Web Service的测试

在上一节里,我们学习了客户端调用服务端中Web Service的方法。在实际应用中,在开放Web Service之前需要进行严格的测试,以保证功能的正确性。在一般框架中,测试Web Service往往这是一个炼狱般痛苦的过程。

XFire通过AbstractXFireTest极大地简化Web Service的测试。AbstractXFireTest允许我们无需构造客户端调用程序,在SOAP报文层面开展对服务端代码的测试,AbstractXFireTest提供了一系列方便的方法对SOAP报文进行验证。XFire还特别为Spring环境下进行Web Service测试提供了一个AbstractXFireSpringTest子类,仅通过启用Spring容器就可以完成Web Service的测试。通过XFire精心设计的测试工具类,对Web Service的测试工作已经是一项可以轻松应对的工作。

如果你在编写服务端Web Service的同时,还需要编写客户端调用程序,这时不可避免的,你希望从客户端角度对Web Service进行测试。由于客户端程序需要访问真实的Web Service,所以需要开启Web服务器,让服务端的Web Service能够提供服务共客户端访问调用。如果客户端和服务端都在同一个项目中开发,XFire允许你在不启动Web服务器的情况下测试客户端程序,其原理是让Web Service运行于JVM模式下。

基于SOAP报文的纯服务端测试

AbstractXFireTest扩展于JUnit标准的TestCase类,提供了向某个Web Service发送SOAP请求报文并对返回的SOAP响应报文进行检验的能力。该测试类提供了若干个方便的断言方法,分别介绍如下:

void assertNoFault(Document node):确认SOAP响应报文无错误;
java.util.List assertValid(java.lang.String xpath, java.lang.Object node):确认在DOM节点特定路径下有对应的元素,路径通过XPath表达式进行定义,该方法还将匹配的元素以List对象返回,你可以对匹配的元素进行进一步的检验;
void assertXPathEquals(java.lang.String xpath, java.lang.String value, Document node):确认特定路径DOM节点为某一特定值;
assertInvalid(java.lang.String xpath, java.lang.Object node):确认DOM节点特定路径下未包含元素。
AbstractXFireSpringTest是AbstractXFireTest的子类,在Spring中你仅需要扩展该类并实现该类的抽象方法ApplicationContext createContext(),就可以对Spring容器中用XFire定义的Web Service进行测试了。

为了测试Web Service,我们必须准备一个SOAP请求报文,你可以简单地手工编写一个,或通过SOAP报文截取工具(如前面我们介绍的TcpTrace、SOAPScope、Apache Axis的TCPMon等)获得一些可用的SOAP请求报文。下面是一个访问BbtForumService 服务的请求SOAP报文:

代码清单6 request_soap.xml:SOAP报文层面测试

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"

xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<soap:Body>

<getRefinedTopicCount

xmlns="http://server.xfire.baobaotao.com">

<in0 xmlns="http://server.xfire.baobaotao.com">20</in0>

</getRefinedTopicCount>

</soap:Body>

</soap:Envelope>

我们将其保存在request_soap.xml文件中放置在类路径com/baobaotao/xfire/server下。当该SOAP请求报文发送给BbtForumService的Web Service后,我们预计它应该返回对应代码清单7所示的正确的SOAP响应报文:

代码清单7 SOAP响应报文

<?xml version="1.0" encoding="UTF-8"?>

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<soap:Body>

<getRefinedTopicCountResponse xmlns="http://www.baobaotao.com">

<out>32</out>

</getRefinedTopicCountResponse>

</soap:Body>

</soap:Envelope>

下面,我们着手编写测试BbtForumService Web Service的测试类,以验证实际SOAP响应报文是否和代码清单7中的一样:

代码清单8 TestBbtForumService

package com.baobaotao.xfire.server;

import org.codehaus.xfire.spring.AbstractXFireSpringTest;

import org.jdom.Document;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestBbtForumService extends AbstractXFireSpringTest {

protected ApplicationContext createContext() {①创建包含Web Service的Spring容器

return new ClassPathXmlApplicationContext(

new String[]);

}

public void testUsingSoapRequest() throws Throwable {

②通过SOAP请求报文访问BbtForumService的Web Service,对返回

SOAP响应报文进行检测

Document response = invokeService("BbtForumService",

"/com/baobaotao/xfire/server/request_soap.xml");

assertNoFault(response);③确认不包含错误

④为命名空间指定一个别名,方便后续XPath表示式的编写

addNamespace("k", "http://www.baobaotao.com");

assertValid("//soap:Body/k:getRefinedTopicCountResponse", response);⑤

assertXPathEquals("//k:getRefinedTopicCountResponse/k:out/text()", "32",response);⑥

printNode(response);⑦打印响应报文,以便肉眼查看

}

}

使用AbstractXFireSpringTest测试Web Service首先要做的第一件事是通过实现createContext()方法构造Spring容器,如①所示。当Spring容器启动时,XFire将自动让容器中的Web Service生效(仅进行测试,不能对外提供服务)。

第二步需要向Web Service发送一个SOAP请求报文以得到一个SOAP响应报文,如②所示。接下来,就是通过AbstractXFireTest提供的检测DOM内容的方法对报文进行正确性验证。由于代码清单7的SOAP报文体中对应的<getRefinedTopicCountResponse>元素及内部元素都位于http://www.baobaotao.com命名空间中,报文体中没有为这个命名空间定义相应的别名,为了在后续断言方法中能够使用简单的方式定义XPath表达式,我们在④处为http://www.baobaotao.com命名空间定义了一个别名。

理解以上测试代码中几个断言方法的关键在于理解XPath表达式语言,XPath语法内容很丰富,不可能在这里逐一讲解,我们在这里介绍一些典型的XPath语法以满足常见的测试需求:

以“/”为前缀的路径表示从DOM根路径开始,如“/soap:Envelope/soap:Body”;
以“//”为前缀的路径表示从DOM任意元素开始查询,如“//out”表示任意元素为out的元素;
元素的属性通过@attrName表示,如“//xsd:complexType[@name="Book"]”表示DOM中任意元素名为complexType并且拥有一个值为Book的name属性的元素;
元素的值通过text()表示,如“//test:Response[text()='32']”表示DOM中任意值为32,元素名为Response,且位于test命名空间中的元素。
现在回过头来看⑤、⑥两处的断言方法,相信大家就可以很容易地理解断言规则了,⑤处的断言检测SOAP响应报文是否包含某一特定元素,而⑥处的断言则对元素内的值进行检测。我们也可以通过printNode()方法将一个节点打印到控制台上,方便肉眼查看。



在JVM模式通过客户端进行测试

能够不启动Web服务器的情况下通过客户端程序测试Web Service的功能,这一崭新的测试方法对于开发人员来说一定深具吸引力。因为,这意味着你可以完全在IDE环境中运行测试,不需要外部环境的支持。

不过享受这一测试好处的应用必须保证客户端和服务端的Web Service都位于同一JVM中,这时请求报文和响应报文直接在JVM 内部通道中传输。当使用JVM内部通道传输请求和响应的SOAP报文时,我们仅需要调整服务的地址就可以了:

代码清单9 TextBbtForumService:JVM模式测试

package com.baobaotao.xfire.client;

import org.codehaus.xfire.client.XFireProxyFactory;

import org.codehaus.xfire.service.Service;

import org.codehaus.xfire.service.binding.ObjectServiceFactory;

import org.codehaus.xfire.spring.AbstractXFireSpringTest;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.baobaotao.xfire.server.BbtForumService;

public class TextBbtForumService extends AbstractXFireSpringTest {

protected ApplicationContext createContext() {

return new ClassPathXmlApplicationContext(

new String[]);

}

public void testGetRefinedTopicCount() throws Throwable {

Service serviceModel = new ObjectServiceFactory().create(BbtForumService.class);

XFireProxyFactory factory = new XFireProxyFactory(getXFire());

①在JVM内部通道中进行SOAP请求和响应报文的传输,请注意粗体所示的服务地址

BbtForumService service = (BbtForumService) factory.create(serviceModel,

"xfire.local://BbtForumService");

int count = service.getRefinedTopicCount(20);

assertEquals(count,32);

}

}

以上代码中,①处的服务地址采用了JVM模式的地址,和其对应的HTTP地址则是http://localhost:8080/baobaotao/service/BbtForumService,所以仅需将服务名前的部分替换为“xfire.local://”就可以了。

小结

比之于Axis,XFire在实施Web Service更加简洁高效,因此XFire在短短的时间里成为了Web Service开发者的炙手可热的框架。更可贵的是XFire对Spring提供了强大的支持,可以非常方便地在Spring中使用XFire实施Web Service。

XFire可以通过多种方式将Spring容器中的Bean导出为Web Service,这包括使用XFireExporter导出器或JSR 181注解。JSR 181和STAX一起都将融入到JDK 6.0中,因此,JSR 181 Web Service定义方式将成为标准的实现。

XFire为客户端提供了多种访问Web Service的方式,如果可以获取客户端的窄接口类,则可以采用窄接口类调用Web Service。如果仅能获取WSDL,XFire也可以采用动态反射的机制调用Web Service。XFire为Eclipse提供了一个可以根据WSDL生成客户端存根代码的插件,相信XFire也将为其它非Java语言提供类似的插件。

技术可用性的一个很大的标准是它是否方便测试,XFire为在Spring中测试Web Service提供了一流的支持,通过JVM模式,你能够在不启动Web容器的情况下测试Web Service,Web Service的测试工作变得不再象原来那样让人畏惧。
分享到:
评论

相关推荐

    使用XFire+Spring构建Web Service

    使用XFire+Spring构建Web Service使用XFire+Spring构建Web Service使用XFire+Spring构建Web Service使用XFire+Spring构建Web Service使用XFire+Spring构建Web Service使用XFire+Spring构建Web Service

    Web Service框架xfire与spring集成开发流程

    XFire 是与Axis 2并列的新一代Web Service框架,通过提供简单的API支持Web Service各项标准协议,帮助你方便快速地...并且因为XFire为Spring提供的支持,使得我们可以很容易在Spring中使用XFire构建Web Service应用。

    使用XFire+Spring构建Web Service(二).doc

    使用XFire+Spring使用XFire+Spring构建Web Service(二).doc构建使用XFire+Spring构建Web Service(二).docWeb Service(二).doc

    使用XFire+Spring构建Web Service步骤以及源代码.rar

    使用XFire+Spring构建Web Service步骤以及源代码.rar

    使用XFire+Spring构建Web Service步骤

    使用XFire+Spring构建Web Service步骤 java

    使用XFire+Spring构建Web+Service

    1 支持一系列Web Service的新标准--JSR181、WSDL2.0 、JAXB2、WS-Security等; 2 使用Stax解释XML,性能有了质的提高。XFire采用Woodstox 作Stax实现; 3 容易上手,可以方便快速地从pojo发布服务; 4 支持...

    webservice例子

    在Spring中使用XFire构建Web Service应用.例子不错,值得下载看看。

    xfire与spring集成案例

    使用XFire+Spring构建Web Service。自己参考网上的讲解写的例子。里面有help.txt 介绍了我参考的xfire+spring集成的网址。

    XFire+Spring webwervice

    使用XFire+Spring构建Web Service.doc 该文章讲解了整个的配置流程,按照该流程可以完成框架搭建。该文章是转载其他人的,因为没有积分,所以不得以而为之。惭愧。

    Spring中文帮助文档

    在应用服务器中使用Hibernate的注意事项 12.3. JDO 12.3.1. 建立PersistenceManagerFactory 12.3.2. JdoTemplate和JdoDaoSupport 12.3.3. 基于原生的JDO API实现DAO 12.3.4. 事务管理 12.3.5. JdoDialect ...

    Spring API

    在应用服务器中使用Hibernate的注意事项 12.3. JDO 12.3.1. 建立PersistenceManagerFactory 12.3.2. JdoTemplate和JdoDaoSupport 12.3.3. 基于原生的JDO API实现DAO 12.3.4. 事务管理 12.3.5. JdoDialect ...

Global site tag (gtag.js) - Google Analytics