以前沒有接觸過CXF,項目需要學習,從網上各種找資料加上項目的實踐,不斷壘字。
CXF (Celtix + XFire)是一個開源的Services框架。CXF 幫助您利用 Frontend 編程 API 來構建和開發 Services ,像 JAX-WS 。這些 Services 可以支持多種協議,比如:SOAP、XML/HTTP、RESTful HTTP 或者 CORBA ,並且可以在多種傳輸協議上運行,比如:HTTP、JMS 或者 JBI,CXF 大大簡化了 Services 的創建,同時它繼承了 XFire 傳統,一樣可以天然地和 Spring 進行無縫集成。
功能特性
CXF 包含了大量的功能特性,但是主要集中在以下幾個方面:
- 支持 Web Services 標准:CXF 支持多種 Web Services 標准,包含 SOAP、Basic Profile、WS-Addressing、WS-Policy、WS-ReliableMessaging 和 WS-Security。
- Frontends:CXF 支持多種“Frontend”編程模型,CXF 實現了 JAX-WS API (遵循 JAX-WS 2.0 TCK 版本),它也包含一個“simple frontend”允許客戶端和 EndPoint 的創建,而不需要 Annotation 注解。CXF 既支持 WSDL 優先開發,也支持從 Java 的代碼優先開發模式。
- 容易使用: CXF 設計得更加直觀與容易使用。有大量簡單的 API 用來快速地構建代碼優先的 Services,各種 Maven 的插件也使集成更加容易,支持 JAX-WS API ,支持 Spring 2.0 更加簡化的 XML 配置方式,等等。
- 支持二進制和遺留協議:CXF 的設計是一種可插撥的架構,既可以支持 XML ,也可以支持非 XML 的類型綁定,比如:JSON 和 CORBA。
支持多種標准
- 支持 JAX-WS、 JAX-WSA、JSR-181 和 SAAJ;
- 支持 SOAP 1.1、1.2、WS-I BasicProfile、WS-Security、WS-Addressing、WS-RM 和 WS-Policy;
- 支持 WSDL 1.1 、2.0;
- 支持 MTOM;
多種傳輸方式、Bindings、Data Bindings 和 Format
- Bindings:SOAP、REST/HTTP;
- Data Bndings:目前支持 JAXB 2.0、Aegis 兩種,默認是 JAXB 2.0。XMLBeans、Castor 和 JiBX 數據綁定方式將在 CXF 2.1 版本中得到支持;
- 格式(Format):XML、JSON;
- 傳輸方式:HTTP、Servlet、JMS 和 Jabber;
- 可擴展的 API 允許為 CXF 增加其它的 Bindings,以能夠支持其它的消息格式,比如:CSV 和固定記錄長度。
靈活部署
- 輕量級容器:可在 Tomcat 或基於 Spring 的容器中部署 Services;
- 集成 JBI:可以在如 ServiceMix, OpenESB or Petals 等等的 JBI 容器中將它部署為一個服務引擎;
- 集成 SCA:可以部署在如 Tuscany 之類的 SCA 容器中;
- 集成 J2EE:可以在 J2EE 應用服務器中部署 Services,比如:Geronimo、JOnAS、JBoss、WebSphere Application Server 和 WebLogic Application Server,以及 Jetty 和 Tomcat;
- 獨立的 Java 客戶端/服務器。
支持多種編程語言
- 全面支持 JAX-WS 2.0 客戶端/服務器編程模型;
- 支持 JAX-WS 2.0 synchronous、asynchronous 和 one-way API's;
- 支持 JAX-WS 2.0 Dynamic Invocation Interface (DII) API;
- 支持 wrapped and non-wrapped 風格;
- 支持 XML messaging API;
- 支持 JavaScript 和 ECMAScript 4 XML (E4X) ,客戶端與服務端均支持;
- 通過 Yoko 支持 CORBA;
- 通過 Tuscany 支持 SCA;
- 通過 ServiceMix 支持 JBI ;
代碼生成
- Java to WSDL;
- WSDL to Java;
- XSD to WSDL;
- WSDL to XML;
- WSDL to SOAP;
- WSDL to Service;
代碼簡單分析
通過查看 Server.java 及 Client.java 的代碼,來了解一下 CXF 的運作過程。Server.java 中主要的代碼片斷如下,它利用 ServerFactoryBean 來進行 Web Services 的發布,實例化一個實現類 HelloWorldImpl,設置將要進行發布的地址 address,最后通過 ServerFactoryBean 的 create() 方法就成功地發布了 Web Services,如此簡單而已,只有六行代碼:
1 HelloWorldImpl helloworldImpl = new HelloWorldImpl(); 2 ServerFactoryBean svrFactory = new ServerFactoryBean(); 3 svrFactory.setServiceClass(HelloWorld.class); 4 svrFactory.setAddress("http://localhost:9000/Hello"); 5 svrFactory.setServiceBean(helloworldImpl); 6 svrFactory.create();
Client.java 中的主要代碼片斷如下,通過 ClientProxyFactoryBean 代理工廠類來創建一個服務,綁定到 endPointAddress 地址,就可以 create 並得到服務,並進行服務消費了:
1 ClientProxyFactoryBean factory = new ClientProxyFactoryBean(); 2 factory.setServiceClass(HelloWorld.class); 3 factory.setAddress("http://localhost:9000/Hello"); 4 HelloWorld client = (HelloWorld)factory.create(); 5 System.out.println("Invoke sayHi()...."); 6 System.out.println(client.sayHi("user"));
CXF 應用開發
下面就將開始我們的 CXF Web Services 的開發之旅!首先,要有一個基於 Eclipse 的開發環境;然后,我們將利用這個開發環境開發一個簡單的“調查投票”示例,同時我們將解釋一些 CXF 在開發中進行配置的基本方法。
接口類創建
在項目的 src 目錄中新建一個 ws.cxf
包,並在里面創建接口類 ISurveyService.java
,為了簡單示示例起見,我們僅創建一個方法 public String vote(String username,int point);
這里要注意的是我們在接口上用 @WebService
注解標明這是一個即將暴露為 Web Service 的接口,並將里面的方法都暴露出去。完整的接口代碼清單如下:
package ws.cxf; import javax.jws.WebService; @WebService public interface ISurveyService { /** * @param username 名字 * @param point 分數 * @return */ public String vote(String username,int point); }
接下來,我們根據接口的定義,來實現它。
具體類實現
針對接口的定義,我們創建一個相應的實現類,並將其定義在 sw.cxf.impl
包中,完整的代碼清單如下:
package ws.cxf.impl; import javax.jws.WebService; import ws.cxf.ISurveyService; @WebService public class SurveyService implements ISurveyService { private String excludeName = "Michael"; private int leastPonit = 5; public String vote(String username,int point) { String result = ""; if(excludeName.equals(username)) { result = " 您不能重復進行投票!"; } else { result = " 謝謝您的投票!"; if(point < leastPonit) { result += " 您的投票分數太低!"; } else { result += " 您的投票分數通過審核!"; } } return result; } // For IoC public String getExcludeName() { return excludeName; } public void setExcludeName(String excludeName) { this.excludeName = excludeName; } public int getLeastPonit() { return leastPonit; } public void setLeastPonit(int leastPonit) { this.leastPonit = leastPonit; } }
接口定義與具體的實現就這樣簡單完成了,接下來就是相關的配置工作了,首先進行 Spring 的 Bean 配置。
Spring 配置
在 src 目錄中創建 beanRefServer.xml 文件,用來定義 Spring 的 Bean 的配置,CXF 支持 Spring 2.0 Schema 標簽配置方式,並且提供快捷暴露 Web Services 的標簽。
首先,我們需要引入 Spring 與 CXF 的命名空間(namespace),如下:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
這樣,我們可以使用 Spring 與 CXF 的標簽配置了。接着,我們需要引入我們所需要的 CXF 的 Bean 定義文件,如下:
<!-- Import Apache CXF Bean Definition --> <import resource="classpath:META-INF/cxf/cxf.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/> <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
接着定義我們具體實現的 Bean ,這個 Bean 的定義與 Spring 普通的 Bean 定義是一樣的:
1 <!-- SurveyService --> 2 <bean id="surveyService" class="ws.cxf.impl.SurveyService"> 3 <property name="excludeName" value="Michael"/> 4 <property name="leastPonit" value="10"/> 5 </bean>
最后,將定義的 Bean 暴露出去成為 Web Service 服務,通過 CXF 提供的 Schema 標簽配置 <jaxws:server>
,這樣定義的配置顯得更加簡潔與方便,定義如下:
<!-- Expose SurveyWebService --> <jaxws:server id="surveyWebService" serviceClass="ws.cxf.ISurveyService" address="/SurveyWebService"> <jaxws:serviceBean> <ref bean="surveyService"/> <!-- 要暴露的 bean 的引用 --> </jaxws:serviceBean> </jaxws:server>
在配置中,serviceClass
的值是我們的接口類的名稱,address
為將要暴露出去的 Web Service 訪問地址。比如:/SurveyWebService
,那么客戶端消費 Web Service 的地址就會成為 http://host:port/WebAPPName/SurveyWebService ,與之相應的 WSDL 地址則為: http://host:port/WebAPPName/SurveyWebService?wsdl 。
Web 應用配置
由於我們的示例是需要通過 Servlet 容器進行服務暴露,因此需要配置相對應的 web.xml 文件,首先是增加 Spring 的配置文件加載 Listener,如下:
1 <!-- Spring Config Location --> 2 <context-param> 3 <param-name>contextConfigLocation</param-name> 4 <param-value>/WEB-INF/classes/beanRefServer.xml</param-value> 5 </context-param> 6 <!-- Spring ContextLoaderListener --> 7 <listener> 8 <listener-class> 9 org.springframework.web.context.ContextLoaderListener 10 </listener-class> 11 </listener>
接下來配置 CXF Servlet 的定義,以及它的映射,如下:
<!-- Apache CXFServlet --> <servlet> <servlet-name>CXFServlet</servlet-name> <display-name>CXF Servlet</display-name> <servlet-class> org.apache.cxf.transport.servlet.CXFServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <!-- CXFServlet Mapping --> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping>
我們將之映射為 /*
。這樣,服務端的代碼與配置就全部完成了,接下來就是將應用程序部署到 Web 容器中去,並驗證服務是否正常發布。
服務器端寫完接下來就可以利用客戶端進行消費了:
消費服務
回到 Eclipse 開發平台,開始編寫消費服務相關的代碼,首先通過 Spring 與 CXF 的配置來定義 Web Service 的客戶端 Bean,在 src 目錄下創建 beanRefClient.xml 配置文件,同樣,我們也需要引入 Spring 與 CXF 命名空間的聲明,並引入 CXF 的 Bean 的定義文件,最后通過與服務端配置相對的 CXF 標簽 <jaxws:client>
來定義客戶端訪問服務的聲明,完整的定義內容如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <!-- Import Apache CXF Bean Definition --> <import resource="classpath:META-INF/cxf/cxf.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/> <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/> <!-- SurveyWebService Client --> <jaxws:client id="surveyServiceClient" serviceClass="ws.cxf.ISurveyService" address="http://localhost:8080/CXF_Spring_Survey/SurveyWebService"/> </beans>
定義說明:id
為 Spring 定義的 id,用來在程序里進行獲取它的標識,serviceClass
仍是為服務端定義的接口類,address
為完整的 Web Service 地址,這個與服務端的定義不一樣。
定義完配置文件,接下來我們編寫訪問的具體代碼,在 test 目錄下創建 ws.cxf.client
包,然后創建 SurveyServiceClient.java,完整的代碼如下:
1 package ws.cxf.client; 2 3 import org.springframework.context.ApplicationContext; 4 import org.springframework.context.support.ClassPathXmlApplicationContext; 5 import ws.cxf.ISurveyService; 6 7 public class SurveyServiceClient 8 { 9 public static void main(String[] args) 10 { 11 // 加載客戶端的配置定義 12 ApplicationContext context = new 13 ClassPathXmlApplicationContext("beanRefClient.xml"); 14 // 獲取定義的 Web Service Bean 15 ISurveyService surveyService = 16 (ISurveyService)context.getBean("surveyServiceClient"); 17 // 1、定義調查投票的變量與內容,用來發送給服務 18 String username = "Test"; 19 int point = 88; 20 // 調用方法進行服務消費 21 String result = surveyService.vote(username,point); 22 System.out.println("Result:" + result); 23 // 2、傳遞不一樣的調查投票內容 24 username = "Michael"; 25 point = 100; 26 // 再次調用方法進行服務消費,得到不一樣的結果 27 result = surveyService.vote(username,point); 28 System.out.println("Result:" + result); 29 // 3、第三次傳遞與調用 30 username = "Jordan"; 31 point = 9; 32 result = surveyService.vote(username,point); 33 System.out.println("Result:" + result); 34 } 35 }
references:
https://www.ibm.com/developerworks/cn/education/java/j-cxf/