<转>XFire生火指南(下)

<转>XFire生火指南(下)

请先阅读:XFire生火指南(上)
1. JSR181

JSR181式通过annotated POJO ,零配置文件的导出Web服务,是BEA倡导的,JavaEE5里的正规方式, XFire作了良好的支持。

但是,XFire关于JSR181方式的文档还不够清晰,请完整阅读本节以避免其中的陷阱。
1.1 参考文章

Spring, Hibernate and XFire
Webservices with Spring, XFire and jsr181
Basic Spring Web services with XFire and JSR 181
XFire JSR181参考文档

1.2 ApplicationContext.xml

因为Web服务配置都写在了annotation,applicationContext.xml文件的内容变得比较固定。需要注意JSR181WebAnnotations与HandlerMapping不能lazy init。

<beans default-autowire="byName">
<!--引入XFire的预配置文件-->
<import resource="classpath:org/codehaus/xfire/spring/xfire.xml"/>

<!-- 获得applicationContext中所有bean的JSR181 annotation -->
<bean id="webAnnotations" class="org.codehaus.xfire.annotations.jsr181.Jsr181WebAnnotations" lazy-init="false"/>


<!-- 定义handler mapping,将所有JSR181定义的bean导出为web service -->
<bean id="jsr181HandlerMapping" class="org.codehaus.xfire.spring.remoting.Jsr181HandlerMapping" lazy-init="false">
<property name="xfire" ref="xfire"/>
<property name="webAnnotations" ref="webAnnotations"/>
</bean>
</beans>

1.3 Interface+Impl模式

不同于XFire传统模式,窄接口不是必须的,只是考虑到有个接口,配置都在接口上做,对原来的Manager类侵入较少。

如果采用Interface,Interface将担任主要的配置工作。

首先定义@WebService,可定义自己的NameSpace,如果不定义将采用默认的生成算法。

接口中的函数将默认全部导出,不需要再用@WebMethod注释,也可以如下例般进行关于Param,Result的更进一步配置:

@WebService(targetNamespace = "http://www.springside.org.cn")
public interface BookService {
@WebResult(name = "SearchResult")
List<Book> findBooksByCategory(@WebParam(name = "category", header = true)String cateoryId);
}

Manager不是纯粹的POJO,需要带上@WebService注释,指明接口。

@WebService(serviceName = "BookService", endpointInterface = "org.springside.bookstore.components.xfire.server.jsr181.BookService")
public class BookManager implements BookService {
...
}

陷阱一:XFire JSR181参考文档 中在Interface中以@WebService(name="BookService")来定义ServiceName,这个做法看起来也比较合理,但实际上需要在Manager中以@WebService(serviceName ="BookService") 来定义,比较古怪。
1.4 纯POJO模式

参考文档中的例子,需要配置@WebMethod 指定需要导出的函数。

@WebService(name = "EchoService", targetNamespace = "http://www.openuri.org/2004/04/HelloWorld")
public class Jsr181EchoService
{
@WebMethod(operationName = "echoString", action = "urn:EchoString")
@WebResult(name = "echoResult")
public String echo(@WebParam(name = "echoParam", header = true) String input)
{
return input;
}
}

1.5 Client注意事项

陷阱二:和传统模式的client有一点最大的区别,serviceModel需要实际的Manager类而不是接口类来做参数:

Service serviceModel = new AnnotationServiceFactory().create(BookManager.class);

2. Client

XFire的Client并不算强项,一共有三种模式:
2.1 Client开发者拥有Web服务端的class

Client与Server是同一个开发团队也好,Server端团队以jar形式提供开发包也好,反正如果能拿到服务端的接口Class和Entity类及aegis 配置文件的话。

传统POJO模式:

Service serviceModel = new ObjectServiceFactory().create(BookService.class);
BookService service = (BookService) new XFireProxyFactory().create(serviceModel, serviceURL);
service.findBooksByCategory(cateoryId);

JSR181模式,注意这里Server端开发组需要向Client提供BookService的实现类BookManager,而不止于接口,有点危险:

Service serviceModel = new AnnotationServiceFactory().create(BookManager.class);
BookService = (BookService) new XFireProxyFactory().create(serviceModel, serviceURL);
service.findBooksByCategory(cateoryId);

SpringSide 用泛型封装了一个XFireClientFactory,调用代码如下:

BookService service = XFireClientFactory.getClient(serviceURL, BookService.class);
BookService service = XFireClientFactory.getJSR181Client(serviceURL, BookService.class, BookManager.class);


2.2 动态模式

动态模式不需要服务端的class,不过性能和复杂对象映射等估计做得不会太好。

Client client = new Client(new URL("http://www.webservicex.net/CurrencyConvertor.asmx?WSDL"));

Object[] results = client.invoke("ConversionRate", new Object[] {"BRL", "UGX"});

2.3 根据WSDL生成Client Stub

这才是Web Service Client的王道,可以访问任意语言编写的Web Service,将在下一个版本中演示。

可以用XFire的Ant Task来生成,但使用MyEclipse的XFire集成会更加方便。生成的代码必须是JDK5.0的版本。
3. 测试

XFiire很重要的一个特性是提供了无须启动Web容器也能进行单元测试的能力。

原理就是利用XFire的JVM模式,以xfire.local://BookService channel而不是http://localhost/service/BookService来访问服务。

测试的方式分两种:

一种是纯服务器角度,不编写客户端代码,以SOAP XML形式发送请求,返回的也是SOAP XML字串,直接对XML进行测试。

一种是编写2.1 中Client代码来进行测试。

前一种的测试的隔离度较高,而后一种比较简便。
3.1 测试基类

无论那种方式,都使用Xfire的AbstractXFireSpringTest基类,实现createContext()回调函数。

protected ApplicationContext createContext() { return ClassPathXmlApplicationContext(new String[]{"classpath*:applicationContext*.xml"});
}

另外测试基类还要完成一个很重要的工作就是要解决Hibernate的LazyLoad问题,做到OpenSession In Test。因此,SpringSide专门封装了一个XFireTestCase的基类。
3.2 用Client代码直接测试

下文直接用client代码调用findBooksByCategory方法,得到返回值后进行各种Assert判断。

注意和普通client code的两处区别:servericeURL换成local,factory须加入getXFire()作参数。

Service serviceModel = new ObjectServiceFactory().create(BookService.class);
XFireProxyFactory factory = new XFireProxyFactory(getXFire());
BookService service = (BookService) factory.create(serviceModel, "xfire.local://BookService");
List list = service.findBooksByCategory("0");
assertNotNull(list);
...

3.3 纯服务端测试

编写一段SOAP XML,以任意命名保存,下文以"Java"作参数,调用findBooksByName方法。

<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<findBooksByName xmlns="http://www.springside.org.cn">
<in1>Java</in1>
</findBooksByName>
</env:Body>
</env:Envelope>

测试代码调用前面的XML,返回XML Document对象,再用基类提供的一些Assert方法检查结果

Document doc = invokeService("BookService","/org/springside/xfire/BookService.FindBooksByName.xml");
assertNoFault(doc);
addNamespace("ss", "http://domain.commons.bookstore.springside.org");
assertValid("//ss:Book/ss:category/ss:descn= \"Java Book\"", doc);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值