xfire

 1.概述

网站:http://xifre.codehaus.org

Smallnest写的 XFire初级中文教程。 

官方网站的User Guide和Quick Start

JavaWorld的介绍文章

XFire是与Axis 2并列的新一代WebService框架。之所以并称为新一代,因为它:

  • 支持一系列Web Service的新标准--JSR181、WSDL2.0 、JAXB2、WS-Security等 ;
  • 使用Stax解释XML,性能有了质的提高。XFire采用Woodstox 作Stax实现;
  • Easily Create Services from POJOs;
  • Spring的结合;
  • 灵活的Binding机制,包括默认的Aegis,xmlbeans,jaxb2,castor。

其中第3,4,5项对一个Pragmatic的应用很重要。SpringSide就是使用了这三样,组合了一个比Axis简单得多的WebService最简做法。

   关注一个WebService框架,通常关注Java代码遵循什么接口和规范,做什么XML配置,最后执行什么命令来发布一个Web Service,另外还关注Java类如何绑定为XML与其他语言沟通,下面将分别介绍XFire里的最简做法。

2.WebService的最快创建

2.1.抽取WebService用的窄接口

BookManger.java只须为POJO即可,不需要含任何WebService相关代码。

为它抽取一个 for WebService的窄接口BookService.java。

窄接口一方面满足了由于安全原因,不愿意整个XXXManager所有方法导出为Web Service的需求,另一方面,XFire暂时也只支持基于接口的Proxy。

2.2.至简单的Aegis Binding

XFire默认的Aegis Binding语法非常简单,int,String,Date等类型的参数和返回值都无需定义,只要定义一下List findBooksByName()的返回值List里的对象是Book就可以了,是我见过最简单的binding定义,大大优于其他以设计复杂为终极目标的方案。

    <mapping>
        <method name="findBooksByName">
            <return-type componentType="org.springside.bookstore.domain.Book"/>
        </method>
</mapping>

为了以约定俗成代替配置,所有Service和Entity Bean的binding文件要求命名为xxx.aegis.xml,而且要和原来的类sit together在同一目录里。

具体介绍见Aegis Binding

2.3.配置Spring 导出Web服务

   配置文件见applicationContext-webservice.xml ,靠一个XFire Exporter将窄接口导出成Web服务,然后靠Spring MVC的URL Mapper将它绑定到某个URL。
    XFire对此还提供了基于XBean的简写法,但我等着Spring2.0,就不上XBean了,抽象出一个parent bean后,其实也差不多了。

   <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <value>/BookService=bookService</value>
        </property>
    </bean> 
 <bean id="bookService" parent="baseWebService">
        <property name="serviceBean" ref="bookManager"/>
        <property name="serviceClass" value="org.springside.bookstore.service.BookService"/>
    </bean>
 <bean id="baseWebService" class="org.codehaus.xfire.spring.remoting.XFireExporter" abstract="true">
        <property name="serviceFactory" ref="xfire.serviceFactory"/>
        <property name="xfire" ref="xfire"/>
</bean>

  此时,XFire就会导出WebService并显示WSDL如下:
      http://localhost:8080/springside/service/BookService?WSDL

另有不依赖于Spring的配置方式,需自行在web.xml配置servlet,在WEB-INF/classes/META-INF/xfire 目录放置services.xml配置文件。

3.Client端代码

1.Client的实现同样只需要POJOs ,Service接口和相应的aegis.xml文件

 public static void main(String[] args) {
   Service serviceModel = new ObjectServiceFactory().create(BookService.class);
  BookService service = (BookService) new XFireProxyFactory().create(
     serviceModel,"http://localhost:8080/springside/service/BookService");
  
List list = service.findBooksByCategory(null);
 }

2.另一种动态Client:

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

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

3. 第三种方式可以尝试使用XFire的WSDL->Server/Client Side代码的ant命令生成基于Jaxb2绑定的Stub。

4.Web Service的单元测试

XFiire提供了AbstractXFireSpringTest 测试类,无须启动Web容器也能进行测试。

1.protected ApplicationContext createContext()方法

你必须实现这个方法将返回定义的ApplicationContext对象。例如:

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

2. 测试服务端

通过invokeService 调用一段写好的web service请求(XML format),可以访问web service,并得到返回的docuemnt,可以调用assertValid验证结果是否正确。

  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);

FindBookByName的内容如下:

<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>

另外如果涉及到hibernate操作,可以使用easyMock,也可以像RealDaoControllerTest那样,自行实现openSession、closeSession操作,避免hibernate lazyload的问题。

3.测试客户端代码

为了在不启动tomcat的情况下测试客户端代码,则测试代码仍然继承于AbstractXFireSpringTest,使用local的URL进行测试

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

注意两处红色的地方,和普通的Client代码略有不同,是解决不用启动tomcat跑客户端service测试代码的关键,其中xfire.local://BookService中的ServiceName 为被Export的接口名,与Spring MVC的URL Mapping无关。

5.安全与认证

可以用WS-Security,Xfire用的是WSS4J ,详看 SpringSide里的服务端配置以及以TestCase形式Demo的客户端代码。 

也可以写一个认证用户名密码的handler。用户名和密码在WebService请求的<head>中编写。在服务端实现一个hanlder负责在header中读出密码并验证,然后把handler挂到service上。

   <bean id="bookWebService" parent="baseWebService">
        <property name="serviceBean" ref="bookManager"/>
        <property name="serviceClass" value="org.springside.bookstore.plugins.xfire.service.BookService"/>
        <property name="inHandlers" ref="authenticationHandler"/>
    </bean>

在客户端同样实现一个handler,负责将用户名和密码放入到请求的head中,在客户端代码中挂接此请求,增加代码

     Client client = ((XFireProxy) Proxy.getInvocationHandler(bookService)).getClient();
     client.addOutHandler(new ClientAuthHandler());

单元测试所编写的web service xml请求也作了相应修改。

6.wsdl2java ant task

在SpringSide的build.xml文件中,增加了wsdl2java的target,利用XFire提供的wsgen task可以从wsdl创建客户端代码。

首先要引入wsgentask,然后调用wsgen:        

<taskdef name="wsgen" classname="org.codehaus.xfire.gen.WsGenTask" classpathref="compile.classpath"/>
<wsgen outputDirectory="${code_path}" wsdl="${wsdl_path}" package="${code_package}" binding="xmlbeans"/>

其中outputDirectory属性定义了代码输出到的文件夹,wsdl定义了wsdl文件的路径,package则定义了创建的java代码的pachage。
binding可以省略,默认binding为JAXB 2.0,也可以设置为xmlbeans,则binding采用xmlbeans的方式。

7.Tips

7.1. Open Session In View

依然是用spring那个filter,对WebService的URL目录也Filter一下:

   <filter-mapping>
        <filter-name>hibernateFilter</filter-name>
        <url-pattern>/service/*</url-pattern>
    </filter-mapping>

7.2 异常处理

以往的模式一般是写一个WebService中间层,负责调用XXXManager,并处理、转化异常。

而XFire是直接export XXXManager的,并提供了一个异常处理的Handler,有默认的实现,也有可扩展的CustomerErrorHandler。

你可能感兴趣的:(spring,bean,Web,xml,webservice)