入门篇1——CXF由来
WebService介绍
   WebService让一个程序可以透明地调用互联网程序,不用管具体的实现细节。只要WebService公开了服务接口,远程客户端就可以调用服务。WebService是基于http协议的组件服务,WebService是分散式应用程序的发展趋势。

WebService的开源实现
   WebService更多是一种标准,而不是一种具体的技术。不同的平台,不同的语言大都提供WebService的开发实现。在JAVA领 域,WebService的框架很多,例如:AXIS,XFire,CXF等。AXIS,XFire相对比较成熟,资料相对较多。在这里我们只对CXF进 行讲解,其他大家想学习到互联网找相关资料学习。

CXF框架由来
   ApacheCXF项目是由ObjectWeb Celtix和CodeHaus XFire合并成立。ObjectWeb Celtix是由IONA公司赞助,于2005年成立的开源Java ESB产品,XFire则是业界知名的SOAP堆栈。合并后的ApacheCXF融合该两个开源项目的功能精华,提供了实现SOA所需要的核心ESB功能 框架,包括SOA服务创建,服务路由,及一系列企业级QoS功能。

ApacheCXF架框的目标
   1.概述
   <>高性能
   <>可扩展
   <>直观易用
   2.支持标准
    <> JAX-WS, JSR-181, SAAJ, JAX-RS
    <> SOAP 1.1, 1.2, WS-I BasicProfile, WS-Security, WS-Addressing, WS-RM, WS-Policy
    <> WSDL 1.1
    <> MTOM
   3.传输方式,绑定,数据绑定,传送数据格式
    <> 绑定: SOAP, REST/HTTP
    <> 数据绑定: JAXB 2.x, Aegis, XMLBeans, SDO
    <> 传送数据格式: XML, JSON, FastInfoset
    <> 传输方式: HTTP, Servlet, JMS
   4.部署灵活
    <> 轻量级: 可以将服务部署到 Tomcat或其支持Spring的容器中
    <> JBI整合: 部署一个服务引擎到JBI容器,例如: ServiceMix, OpenESB or Petals
    <> J2EE集成: 可以将服务部署到J2EE应用服务器上,例如:Geronimo, JOnAS, JBoss, WebLogic, 及WebSphere
    <> Java 客户端/服务端可以独立性
   5.支持多种编程语言
    <> 完全支持 JAX-WS 2.x 客户端/服务端模式
    <> JAX-WS 2.x synchronous, asynchronous and one-way API's
    <> JAX-WS 2.x Dynamic Invocation Interface (DII) API
    <> 支持 wrapped and non-wrapped 数据格式
    <> XML messaging API
    <> 支持JavaScript 和 ECMAScript 4 XML (E4X)
    <> 支持CORBA
    <> 支持JBI及ServiceMix
   6.可编程环境
    <> Java to WSDL
    <> WSDL to Java
    <> XSD to WSDL
    <> WSDL to XML
    <> WSDL to SOAP
    <> WSDL to service

 

入门篇2——HelloWorld

理论联系实际,单单只讲理论那就成了纸上谈兵,用一个HelloWorld Demo可来说明事更加直观。那下面咱们就开始进行讲解:
   首先到apache官方网下载apache-cxf-2.2.2,地址:http://cxf.apache.org/
   新建一个Java Project,导入cxf常用.jar包
Java代码
1. commons-logging-1.1.1.jar   
2. geronimo-activation_1.1_spec-1.0.2.jar (or Sun's Activation jar)   
3. geronimo-annotation_1.0_spec-1.1.1.jar (JSR 250)   
4. geronimo-javamail_1.4_spec-1.6.jar (or Sun's JavaMail jar)   
5. geronimo-servlet_2.5_spec-1.2.jar (or Sun's Servlet jar)   
6. geronimo-ws-metadata_2.0_spec-1.1.2.jar (JSR 181)   
7. geronimo-jaxws_2.1_spec-1.0.jar (or Sun's jaxws-api-2.1.jar)   
8. geronimo-stax-api_1.0_spec-1.0.1.jar (or other stax-api jar)   
9. jaxb-api-2.1.jar   
10. jaxb-impl-2.1.12.jar   
11. jetty-6.1.21.jar   
12. jetty-util-6.1.21.jar   
13. neethi-2.0.4.jar   
14. saaj-api-1.3.jar   
15. saaj-impl-1.3.2.jar   
16. wsdl4j-1.6.2.jar   
17. wstx-asl-3.2.8.jar   
18. XmlSchema-1.4.5.jar   
19. xml-resolver-1.2.jar   
20. cxf-2.2.2.jar  

   接下就是HelloWorld Demo开发了
   第一步:新建一个webservice接口
Java代码
1. @WebService  
2. public interface IHelloWorld {   
3.     //@WebParam给参数命名,提高可代码可读性。此项可选   
4. blic String sayHi(@WebParam(name="text") String text);   
5. }  

   通过注解@WebService申明为webservice接口
   第二步,实现WebService接口
Java代码
1.   @WebService  
2.   public class HelloWorldImpl implements IHelloWorld {   
3.   
4. public String sayHi(String name) {   
5.      System.out.println("sayHello is called by " + name);   
6.     return "Hello " + name;   
7. }   
8.   
9.     }  

   第三步,创建服务端
Java代码
1.   public class Server {   
2.   
3. private Server(){   
4.      IHelloWorld helloWorld = new HelloWorldImpl();   
5.     //创建WebService服务工厂   
6.      JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();   
7.     //注册WebService接口   
8.      factory.setServiceClass(IHelloWorld.class);   
9.     //发布接口   
10.      factory.setAddress("http://localhost:9000/HelloWorld");   
11.      factory.setServiceBean(helloWorld);   
12.     //创建WebService   
13.      factory.create();   
14. };   
15.   
16. public static void main(String[] args) throws InterruptedException{   
17.        //启动服务端   
18.               new Server();   
19.      System.out.println("Server ready...");   
20.     //休眠一分钟,便于测试   
21.                 Thread.sleep(1000*60);   
22.      System.out.println("Server exit...");   
23.      System.exit(0);   
24. }   
25.     }  

    第四步,创建客户端
  
Java代码
1.    public class Client {   
2.   
3. private Client(){};   
4.   
5. public static void main(String[] args){   
6.     //创建WebService客户端代理工厂   
7.      JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();   
8.     //注册WebService接口   
9.      factory.setServiceClass(HelloWorld.class);   
10.     //设置WebService地址   
11.      factory.setAddress("http://localhost:9000/HelloWorld");        
12.      IHelloWorld iHelloWorld = (IHelloWorld)factory.create();   
13.      System.out.println("invoke webservice...");   
14.      System.out.println("message context is:"+iHelloWorld.sayHi("     
15.                   Josen"));   
16.      System.exit(0);   
17. }   
18.     }   
19.     


    最后是万事俱备,只欠测试了
    首先,运行服务端程序
    其次,打开浏览器,在地址栏中输入http://localhost:9000/HelloWorld?wsdl(因为cxf自带了一个jetty服务器),查看接口是否发布成功,如里浏览器页面显示下面内容,证明接口发布成功
Java代码
1.     <wsdl:definitions name="IHelloWorldService" targetNamespace="http://client.itdcl.com/">   
2. <wsdl:types>   
3. <xsd:schema attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://client.itdcl.com/">   
4. <xsd:element name="sayHi" type="tns:sayHi"/>   
5. <xsd:complexType name="sayHi">   
6. <xsd:sequence>   
7. <xsd:element minOccurs="0" name="text" type="xsd:string"/>   
8. </xsd:sequence>   
9. </xsd:complexType>   
10. <xsd:element name="sayHiResponse" type="tns:sayHiResponse"/>   
11. <xsd:complexType name="sayHiResponse">   
12. <xsd:sequence>   
13. <xsd:element minOccurs="0" name="return" type="xsd:string"/>   
14. </xsd:sequence>   
15. </xsd:complexType>   
16. </xsd:schema>   
17. </wsdl:types>   
18. <wsdl:message name="sayHi">   
19. <wsdl:part element="tns:sayHi" name="parameters">   
20.      </wsdl:part>   
21. </wsdl:message>   
22. <wsdl:message name="sayHiResponse">   
23. <wsdl:part element="tns:sayHiResponse" name="parameters">   
24.      </wsdl:part>   
25. </wsdl:message>   
26. <wsdl:portType name="IHelloWorld">   
27. <wsdl:operation name="sayHi">   
28. <wsdl:input message="tns:sayHi" name="sayHi">   
29.      </wsdl:input>   
30. <wsdl:output message="tns:sayHiResponse" name="sayHiResponse">   
31.      </wsdl:output>   
32. </wsdl:operation>   
33. </wsdl:portType>   
34. <wsdl:binding name="IHelloWorldServiceSoapBinding" type="tns:IHelloWorld">   
35. <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>   
36. <wsdl:operation name="sayHi">   
37. <soap:operation soapAction="" style="document"/>   
38. <wsdl:input name="sayHi">   
39. <soap:body use="literal"/>   
40. </wsdl:input>   
41. <wsdl:output name="sayHiResponse">   
42. <soap:body use="literal"/>   
43. </wsdl:output>   
44. </wsdl:operation>   
45. </wsdl:binding>   
46. <wsdl:service name="IHelloWorldService">   
47. <wsdl:port binding="tns:IHelloWorldServiceSoapBinding" name="IHelloWorldPort">   
48. <soap:address location="http://localhost:9000/HelloWorld"/>   
49. </wsdl:port>   
50. </wsdl:service>   
51. </wsdl:definitions>


入门篇3——WSDL描述

   由于网上有很多相关这方面的资料,在这里我就转载http://www.ibm.com/developerworks/cn/webservices/ws-wsdl/index.html一篇,不再重新讲述了。
    本文初步介绍了Web Service 'stack'中对于Web服务即时装配,自动集成起着关键作用的WSDL规范,首先介绍了WSDL的作用和意义,其次对WSDL文档的结构作出概要地介 绍,对每个元素的作用作了探讨,分析了其开放和复用的体系设计的思想,最后通过一个实例详细说明了WSDL的工作模式。

    本文所引用的资源主要包括两类,一类是Web服务的技术资源网站,包含了大量Web服务的技术信息,另一类是Web服务“stack"系列技术规范,他们 是一个整体的技术体系,包括UDDI、SOAP、WSDL、XML等。本文的最后给出了这些资源的链接,有兴趣的读者可以通过这些资源链接找到所需的内 容。

Web Service "Stack"

    在我的先前的文章中,我已经介绍过Web服务的整个技术体系Web Service "stack",如下图:

Figure 1. Web Service "stack"

 

 

其中,绿色部分是先前已经定义好的并且广泛使用的传输层和网络层的标准:IP、HTTP、SMTP等。而蓝色部分是目前开发的Web服务的相关标准 协议,包括服务调用协议SOAP、服务描述协议WSDL和服务发现/集成协议UDDI,以及服务工作流描述语言WSFL。而橙色部分描述的是更高层的待开 发的关于路由、可靠性以及事务等方面的协议。×××部分是各个协议层的公用机制,这些机制一般由外部的正交机制来完成。

其中,一个可以使用的Web服务应当按照需要选用若干层次的功能,而无需所有的特性。但是无论如何为了实现一个一般意义上的Web服务,具备Web 服务的基础特性:跨平台调用和接口可机器识别,那么必需使用WSDL和SOAP。SOAP是用来最终完成Web服务调用的,而WSDL则是用于描述如何使 用 SOAP来调用Web服务的。

    WSDL 是一种XML Application,他将Web服务描述定义为一组服务访问点,客户端可以通过这些服务访问点对包含面向文档信息或面向过程调用的服务进行访问(类似 远程过程调用)。WSDL首先对访问的操作和访问时使用的请求/响应消息进行抽象描述,然后将其绑定到具体的传输协议和消息格式上以最终定义具体部署的服 务访问点。相关的具体部署的服务访问点通过组合就成为抽象的Web服务。

    在具体使用中,我们可以对 WSDL 进行扩展(类似SOAP的可扩展性),这样无论通信时使用何种消息格式或网络协议,都可以对服务访问点及其使用的消息格式进行描述。在WSDL的框架中, 可以使用任意的消息格式和网络协议,如同SOAP中可以使用任意的网络协议一样。在WSDL规范中,定义了如何使用SOAP消息格式、HTTP GET/POST消息格式以及MIME格式来完成Web服务交互的规范。
WSDL概述
    由于通信协议和消息格式在 Web 技术圈子里已经达到了标准化,我们知道在通常的开发过程中,对于对象的Interface一定具备相应的SDK描述文档,Web服务也是一种对象,只不过 它是被部署在Web上而已。很自然的,我们也完全需要有对Web服务这个对象的界面的SDK描述文档。然而这两者又不尽相同,一来目前在Web上的应用已 经完全接受了XML这个基本的标准,基本上所有新出台的技术都是基于XML标准的,二来Web服务的目标是即时装配,松散耦合以及自动集成的,这意味着 SDK描述文档应当是具备被机器识别的能力的。

    也就是说,对于使用标准化的消息格式/通信协议的Web服务,它需要以某种结构化的方式(即XML)对Web服务的调用/通信加以描述,而且实现这一点也 显得非常重要,这是Web服务即时装配的基本保证。WSDL正是这样一种描述语言,WSDL 定义了一套基于 XML的语法,将Web服务描述为能够进行消息交换的服务访问点的集合,从而满足了这种需求。WSDL 服务定义为分布式系统提供了可机器识别的SDK文档,并且可用于描述自动执行应用程序通信中所涉及的细节。

    WSDL 文档将Web服务定义为服务访问点或端口的集合。在 WSDL 中,由于服务访问点和消息的抽象定义已从具体的服务部署或数据格式绑定中分离出来,因此可以对抽象定义进行再次使用:消息,指对交换数据的抽象描述;而端 口类型,指操作的抽象集合。用于特定端口类型的具体协议和数据格式规范构成了可以再次使用的绑定。将Web访问地址与可再次使用的绑定相关联,可以定义一 个端口,而端口的集合则定义为服务。因此,WSDL 文档在Web服务的定义中使用下列元素:

    * Types - 数据类型定义的容器,它使用某种类型系统(一般地使用XML Schema中的类型系统)。
    * Message - 通信消息的数据结构的抽象类型化定义。使用Types所定义的类型来定义整个消息的数据结构。
    * Operation - 对服务中所支持的操作的抽象描述,一般单个Operation描述了一个访问入口的请求/响应消息对。
    * PortType - 对于某个访问入口点类型所支持的操作的抽象集合,这些操作可以由一个或多个服务访问点来支持。
    * Binding - 特定端口类型的具体协议和数据格式规范的绑定。
    * Port - 定义为协议/数据格式绑定与具体Web访问地址组合的单个服务访问点。
    * Service - 相关服务访问点的集合。

大家可以参考下图,来理解一下WSDL文档的结构组织:

Figure 2. WSDL元素的对象结构示意图

 




 

 

    其中,Types是一个数据类型定义的容器,包含了所有在消息定义中需要的XML元素的类型定义,我将在今后的文章中结合XML Schema来详细说明如何进行类型定义。

    Message具体定义了在通信中使用的消息的数据结构,Message元素包含了一组Part元素,每个Part元素都是最终消息的一个组成部分,每个 Part都会引用一个DataType来表示它的结构。Part元素不支持嵌套(可以使用DataType来完成这方面的需要),都是并列出现。

    PortType具体定义了一种服务访问入口的类型,何谓访问入口的类型呢?就是传入/传出消息的模式及其格式。一个PortType可以包含若干个 Operation,而一个Operation则是指访问入口支持的一种类型的调用。在WSDL里面支持四种访问入口调用的模式:

   1. 单请求;
   2. 单响应;
   3. 请求/响应;
   4. 响应/请求。

    在这里请求指的是从客户端到Web服务端,而响应指的是从Web服务端到客户端。PortType的定义中会引用消息定义部分的一个到两个消息,作为请求 或响应消息的格式。比如,一个股票查询的访问入口可能就会支持两种请求消息,一种请求消息中指明股票代码,而另一种请求消息中则会指明股票的名称,响应消 息可能都是股票的价格等等。

    以上三种结构描述了调用Web服务的抽象定义,这三部分与具体Web服务部署细节无关,是可复用的描述(每个层次都可以复用)。如果与一般的对象语言做比 较的话,这部分可以堪称是IDL描述的对象,描述了对象的接口标准,但是到底对象是用哪种语言实现,遵从哪种平台的细节规范,被部署在哪台机器上则是后面 的元素所描述的。

    Service描述的是一个具体的被部署的Web服务所提供的所有访问入口的部署细节,一个Service往往会包含多个服务访问入口,而每个访问入口都会使用一个Port元素来描述。

    Port描述的是一个服务访问入口的部署细节,包括通过哪个Web地址(URL)来访问,应当使用怎样的消息调用模式来访问等。其中消息调用模式则是使用Binding结构来表示。

    Binding结构定义了某个PortType与某一种具体的网络传输协议或消息传输协议相绑定,从这一层次开始,描述的内容就与具体服务的部署相关了。 比如可以将PortType与SOAP/HTTP绑定,也可以将PortType与MIME/SMTP相绑定等。

    在介绍了WSDL的主要元素之后,大家会发现,WSDL的设计理念完全继承了以XML为基础的当代Web技术标准的一贯设计理念:开放。WSDL允许通过 扩展使用其他的类型定义语言(不光是XML Schema),允许使用多种网络传输协议和消息格式(不光是在规范中定义的这些:SOAP/HTTP,HTTP-GET/POST以及MIME等)。同 时WSDL也应用了当代软件工程中的复用理念,分离了抽象定义层和具体部署层,使得抽象定义层的复用性大大增加。比如我们可以先使用抽象定义层为一类 Web服务进行抽象定义(比如UDDI Registry,抽象定义肯定是完全一致的遵循了UDDI规范),而不同的运营公司可以采用不同的具体部署层的描述结合抽象定义完成其自身的Web服务 的描述。


WSDL文档示例
    下例是一个提供股票报价的简单Web服务的 WSDL 定义。该服务支持名为 GetLastTradePrice 的单一操作,这个操作是通过在 HTTP 上运行 SOAP 1.1 协议来实现的。该请求接受一个类型为字符串的 tickerSymbol,并返回类型为浮点数的价格。
Java代码
1. <?xml version="1.0"?>   
2. <definitions name="StockQuote"   
3.               targetNamespace="http://example.com/stockquote.wsdl"  
4.               xmlns:tns="http://example.com/stockquote.wsdl"  
5.               xmlns:xsd1="http://example.com/stockquote.xsd"  
6.               xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"  
7.               xmlns="http://schemas.xmlsoap.org/wsdl/">   
8.                 
9.   
10.    <types>   
11.      <schema targetNamespace="http://example.com/stockquote.xsd"  
12.              xmlns="http://www.w3.org/1999/XMLSchema">   
13.        <element name="TradePriceRequest">   
14.          <complexType>   
15.            <all>   
16.              <element name="tickerSymbol" type="string"/>   
17.            </all>   
18.          </complexType>   
19.        </element>   
20.        <element name="TradePriceResult">   
21.          <complexType>   
22.            <all>   
23.              <element name="price" type="float"/>   
24.            </all>   
25.          </complexType>   
26.        </element>   
27.      </schema>   
28.    </types>  

    上面这部分是数据类型的定义,其中为定义了两个元素的结构:

    * TradePriceRequest(交易价格请求): 将该元素定义为包含一个字符串元素(tickerSymbol)的复合类型元素。
    * TradePriceResult(交易价格): 将该元素定义为一个包含一个浮点数元素(price)的复合类型元素。
Java代码
1. <message name="GetLastTradePriceInput">   
2.      <part name="body" element="xsd1:TradePriceRequest"/>   
3.    </message>   
4.   
5.    <message name="GetLastTradePriceOutput">   
6.      <part name="body" element="xsd1:TradePriceResult"/>   
7.    </message>  

    这部分是消息格式的抽象定义,其中定义了两个消息格式:

    * GetlastTradePriceInput(获取最后交易价格的请求消息格式): 由一个消息片断组成,该消息片断的名字是body,包含的具体元素类型是TradePriceRequest。(前面已经定义过了)
    * GetLastTradePriceOutput(获取最后交易价格的响应消息格式) : 由一个消息片断组成,该消息片断的名字是body,包含的具体元素类型是TradePriceResult。(前面已经定义过了)
Java代码
1. <portType name="StockQuotePortType">   
2.     <operation name="GetLastTradePrice">   
3.       <input message="tns:GetLastTradePriceInput"/>   
4.       <output message="tns:GetLastTradePriceOutput"/>   
5.     </operation>   
6. </portType>  

    这部分定义了服务访问点的调用模式的类型,表明StockQuoteService的某个入口类型是请求/响应模式,请求消息是GetlastTradePriceInput,而响应消息是GetLastTradePriceOutput。
Java代码
1. <binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType">   
2.      <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>   
3.        <operation name="GetLastTradePrice">   
4.          <soap:operation soapAction="http://example.com/GetLastTradePrice"/>   
5.            <input>   
6.              <soap:body use="literal" namespace="http://example.com/stockquote.xsd"  
7.                         encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>   
8.            </input>   
9.            <output>   
10.              <soap:body use="literal" namespace="http://example.com/stockquote.xsd"  
11.                         encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>   
12.            </output>   
13.          </soap:operation>   
14.        </operation>   
15.      </soap:binding>   
16.    </binding>  

    这部分将服务访问点的抽象定义与SOAP HTTP绑定,描述如何通过SOAP/HTTP来访问按照前面描述的访问入口点类型部署的访问入口。其中规定了在具体SOAP调用时,应当使用的 soapAction是"http://example.com/GetLastTradePrice",而请求/响应消息的编码风格都应当采用SOAP 规范默认定义的编码风格" http://schemas.xmlsoap.org/soap/encoding/"。
Java代码
1. <service name="StockQuoteService">   
2.      <documentation>股票查询服务</documentation>   
3.      <port name="StockQuotePort" binding="tns:StockQuoteBinding">   
4.      <soap:address location="http://example.com/stockquote"/>   
5.      </port>   
6.    </service>   
7.   
8. </definitions>  

    这部分是具体的Web服务的定义,在这个名为StockQuoteService的Web服务中,提供了一个服务访问入口,访问地址是"http://example.com/stockquote",使用的消息模式是由前面的binding所定义的。

    按照这个WSDL文档的描述,在具体Web服务的使用中,具体发生的SOAP交互可能如下面所示:

SOAP消息请求:
Java代码
1. POST /StockQuote HTTP/1.1  
2. Host: example.com   
3. Content-Type: text/xml; charset="utf-8"  
4. Content-Length: nnnn   
5. SOAPAction: "http://example.com/GetLastTradePrice"  
6.   
7. <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"  
8.                     SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">   
9.    <SOAP-ENV:Body>   
10.      <m:TradePriceRequest xmlns:m="http://example.com/stockquote.xsd">   
11.        <tickerSymbol>MSFT</tickerSymbol >   
12.      </m:TradePriceRequest>   
13.    </SOAP-ENV:Body>   
14. </SOAP-ENV:Envelope>  

SOAP消息响应:
Java代码
1. HTTP/1.1 200 OK   
2. Content-Type: text/xml; charset="utf-8"  
3. Content-Length: nnnn   
4.   
5. <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"  
6.                     SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>   
7.    <SOAP-ENV:Body>   
8.      <m:TradePriceResult xmlns:m=" http://example.com/stockquote.xsd ">   
9.        <price>74.5</price>   
10.      </m:TradePriceResult >   
11.    </SOAP-ENV:Body>   
12. </SOAP-ENV:Envelope>  

小结
    在本文中,我简单介绍了WSDL规范的用途