引言
Axis2 是下一代 Apache Axis。Axis2 雖然由 Axis 1.x 處理程序模型提供支持,但它具備更強的靈活性並可擴展到新的體系結構。Axis2 基於新的體系結構進行了全新編寫,並且沒有采用 Axis 1.x 的經常使用代碼。支持開發 Axis2 的動力是探尋模塊化更強、靈活性更高和更有效的體系結構,這種體系結構能夠很容易地插入到其餘相關 Web 服務標準和協議(如 WS-Security、WS-ReliableMessaging 等)的實現中。
Axis2 的特性包括:
採用名爲 AXIOM(AXIs Object Model,Axis 對象模型)的新核心 XML 處理模型
支持 In-Only 和 In-Out 消息交換模式 (MEP)
阻塞和非阻塞客戶端 API(應用程序編程接口)
支持內置的 Web 服務尋址 (WS-Addressing)
支持 XMLBeans 數據綁定
新部署模型
支持超文本傳輸協議 (HTTP)、簡單郵件傳輸協議 (SMTP) 和傳輸控制協議 (TCP) 等傳輸協議
本系列文章以 Axis2 1.0 版本爲基礎。您能夠在 Apache 網站得到 Axis2 的最新版本。
Axis 體系結構概述
圖 1. Axis2 體系結構
Axis2 體系結構將邏輯與狀態分離;這容許在並行線程中執行邏輯。服務和調用的靜態狀態和動態狀態分別存儲在 Description 和 Context 類中。Axis2 體系結構是使用 7 個獨立模塊實現的。
信息模型:此模塊管理 SOAP 引擎的狀態。該模型定義一組用於存放狀態的類,而引擎管理這些信息對象的生命週期。信息模型包含兩種用於存放狀態的類。Description 類存放本質上是靜態的且存在於 Axis 引擎實例的整個生命週期中的數據(如傳輸、服務和操做的配置)。Context 類存放調用上下文中有效的服務和操做的動態信息,例如當前請求和響應 SOAP 消息、From 地址、To 地址和其餘元素。
XML 處理模型:Axis2 引入了一個名爲 AXIOM 的新模型,用於處理 SOAP 消息。AXIOM 使用 StAX (Streaming API for XML) 來解析 XML。StAX 是一個標準的流式 Pull 解析器 Java™ API。AXIOM 很是精巧,不會減慢 XML 信息集的構建速度——換句話說,對象只有在絕對必要時纔會建立。整體而言,AXIOM 和 Axis2 所佔用的內存要小於 Axis 1 所佔用的內存。
SOAP 處理模型:Axis2 體系結構定義了兩個管道(或流),分別稱爲 InPipe (InFlow) 和 OutPipe (OutFlow),用於處理服務器端的請求消息和響應消息。在客戶端,這兩個管道是反向的——換句話說,SOAP 請求消息流經 OutPipe,而響應消息流經 InPipe。管道或流包含一系列分爲階段的處理程序。階段按照預先定義的順序執行,如上面的圖 1 所示。除預先定義的階段和處理程序集外,用戶還能夠在操做級別、服務級別或全局級別配置用戶階段和相關處理程序。處理程序充當 SOAP 消息的攔截器,能夠處理 SOAP 消息的 Header 或 Body。InPipe 是經過如下階段進行配置的:
TransportIn
PreDispatch
Dispatch
PostDispatch
PolicyDetermination
User phases
Message validation
咱們將在本系列文章的第 2 部分中詳細介紹上述各階段。請求消息在經過 Inpipe 中配置的全部階段後,到達 MessageReceiver,而後由 MessageReceiver 調用實際服務實現。服務器的 OutPipe 包含如下階段:
Message initialization
Policy determination
User phases
MessageOut
用 戶配置的階段位於這兩個管道的用戶階段(User phases) 部分。若是在執行這些管道的過程當中發生錯誤,則這些錯誤將經過 InFaultPipe 或 OutFaultPipe 管道。收到 Fault 消息後,在客戶端調用 InFaultPipe;若是某個調用致使將錯誤發送到客戶端,則在服務器端調用 OutFaultPipe。用戶能夠將處理程序添加到預先定義的階段,而且按照這些處理程序運行的順序進行配置。
部署模塊:此模塊配置 Axis 引擎並部署服務和模塊。axis2.xml(在 webapps/axis2/WEB-INF 中)包含 Axis2 引擎的全局配置,包括:
全局模塊 (Global modules)
全局接收器 (Global receivers)
傳輸 (Transports)
用戶階段定義 (User phase definitions)
每一個服務的配置都包含在服務存檔的 services.xml 文件中。本文稍後將詳細討論此文件。
WSDL 和代碼生成:此模塊從 WSDL 文件中生成客戶端存根和服務器框架代碼。Axis2 代碼生成器發出採用正確 XML 樣式表的 XML 文件,以用所需語言生成代碼。
客戶端 API:Axis2 客戶端 API 調用遵循 WSDL 2.0 定義的 In-Only 和 In-Out 消息模式的操做。客戶端 API 支持 In-Out 操做的阻塞和非阻塞調用。
傳輸:此模塊包含與傳輸層交互的處理程序。傳輸處理程序有兩種類型:TransportListener 和 TransportSender。TransportListener 從傳輸層接收 SOAP 消息,而後將其傳送到 InPipe 進行處理。TransportSender 發送經過指定傳輸從 OutPipe 接收到的 SOAP 消息。Axis2 提供 HTTP、SMTP 和 TCP 的處理程序。對於 HTTP 傳輸,服務器端上的 AxisServlet 和客戶端上的一個簡單的獨立 HTTP 服務器(由 Axis2 提供)充當 TransportReceiver。
回頁首
部署 Axis2
部署 Axis2 與部署 Axis 1 同樣簡單。首先在 Axis2 二進制代碼分發包的 webapps 目錄下查找 Axis2 Web 應用程序 axis2.war。在 servlet 容器中部署此 war 文件。在 Tomcat 中,若是已在服務器配置中將 unpackWARs 設置爲 True,則只需將 axis2.war 複製到 $TOMCAT_HOME/webapps 目錄便可部署 Axis2。請當即啓動 Tomcat 並訪問 http://localhost:<port>/axis2。將顯示 Axis2 歡迎頁,單擊此頁上的 Validate 連接。您應到達 Axis2 Happiness page,不會出現任何錯誤。
回頁首
開發 StockQuoteService
下 面介紹如何使用 In-Only subscribe() 和 In-Out getQuote() 這兩個操做來開發 StockQuoteService。subscribe() 操做將預訂指定代號的每小時報價,而 getQuote() 將得到指定代號的當前報價。
下面的清單 1 是 StockQuoteService 的實現示例:
清單 1. StockQuoteService 實現
package stock;import org.apache.axiom.om.OMAbstractFactory;import org.apache.axiom.om.OMElement;import org.apache.axiom.om.OMFactory;import org.apache.axiom.om.OMNamespace; public class StockQuoteService { public void subscribe(OMElement in){ String symbol = in.getText(); System.out.println("Subscription request for symbol ="+symbol); // put the actual subscribe code here... } public OMElement getQuote(OMElement in){ // Get the symbol from request message String symbol = in.getText(); int quote = 0; if(symbol.equals("IBM")){ quote = 100; } // Put more quotes here ... // Create response OMFactory fac = OMAbstractFactory.getOMFactory(); OMNamespace omNs = fac.createOMNamespace( "http://www.developerworks.com/example", "example"); OMElement resp = fac.createOMElement("getQuoteResponse", omNs); resp.setText(String.valueOf(quote)); return resp; }}
Axis2中的om子包在V1.0版本中今後前的axis2包移至axiom包中。
回頁首
部署服務
部署描述符
在 Axis2 中,服務部署信息包含在 services.xml 文件(在 0.92 之前的版本中,此文件名爲 service.xml)中。對於上述 StockQuoteService,服務部署描述符與下面的清單 2 相似。
清單 2. Services.xml
<service name="StockQuoteService"> <parameter name="ServiceClass" locked="xsd:false"> stock.StockQuoteService </parameter> <operation name="getQuote"> <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/> </operation> <operation name="subscribe"> <messageReceiver class="org.apache.axis2.receivers.RawXMLINOnlyMessageReceiver"/> </operation></service>
服務的 name 屬性定義服務的名稱。Axis2 使用服務的名稱建立服務的端點地址,例如 http://localhost:<port>/axis2/services/<nameofservice>。所以,對於 StockQuoteService,服務端點爲 http://localhost:<port>/axis2/services/StockQuoteService。ServiceClass 參數指定服務實現類。
每一個 <operation> 元素定義服務中一個操做的配置。<operation> 的 name 屬性應設置爲服務實現類中方法的名稱。messageReceiver 元素定義用於處理此操做的消息接收器。Axis2 針對 In-Only 和 In-Out 操做提供了兩個無數據綁定的內置 MessageReceivers;org.apache.axiom.receivers.RawXMLINOnlyMessageReceiver 用於 In-Only 操做,而 org.apache.axiom.receivers.RawXMLINOutMessageReceiver 用於 In-Out 操做。若是沒有指定 messageReceiver,則 Axis2 將嘗試使用 org.apache.axiom.receivers.RawXMLINOutMessageReceiver 做爲缺省的 messageReceiver。上述 RAWXML 消息接收器將傳入 SOAP 消息的 <Body> 的內容做爲 OMElement(OMElement 是 XML 元素的 AXIOM 縮寫)傳遞給服務實現。此操做應做爲 OMElement 返回 SOAP 響應的 <Body> 元素包含的 XML 內容。這便解釋了爲什麼 subscribe() 和 getQuote() 操做採用和返回 OMElement。
services.xml 還能夠包含分爲 servicegroup 的多個服務。
打包
Axis 2 服務是做爲 Axis Archive (.aar) 打包的。這是一個 JAR 文件(使用 jar 或 zip 實用程序建立),在存檔的 META-INF 目錄中打包了 services.xml 文件。StockQuoteService 在打包成 StockQuoteService.aar 時將具備如下結構:
./stock/StockQuoteService.class./META-INF/services.xml
預先打包的 StockQuoteService 存檔能夠在本文的下載部分中找到。
因 爲StockQuoteService沒有采用RPC方式的消息接收器,用StockQuoteService?wsdl方式不能自動生成wsdl文件, 解決辦法是手工或用其它工具生成相應的wsdl文件,將其打包在StockQuoteService.aar中。此時StockQuoteService 打包成 StockQuoteService.aar 將具備如下結構:
./stock/StockQuoteService.class./META-INF/services.xml./META-INF/services.wsdl
部署
在 Axis2 中部署服務至關簡單,只需將 .aar 文件複製到 servlet 容器的 axis2 Web 應用程序中的 axis2/WEB-INF/services 目錄下便可。對於 Tomcat,此位置爲 $TOMCAT_HOME/webapps/axis2/WEB-INF/services。
另外一種部署服務的好方法是使用 Axis2 管理控制檯中的 Upload Service 工具。請轉到 http://localhost:<port>/axis2,而後選擇 Administration 連接。輸入用戶名和密碼 admin/axis2,而後登陸。(您能夠在 axis2.xml 中配置用戶名/密碼。)在工具部分選擇 Upload Service 連接,再選擇 .aar 文件,而後單擊 Upload。就是這樣簡單!若是上傳成功,系統將顯示一條綠色成功消息。服務即被部署,並且可隨時調用。若是要在遠程 Axis2 服務器上部署服務,則此功能很是方便。
回頁首
經過 Axis2 使用 Web 服務
Web 服務調用的特性由 MEP、傳輸協議以及客戶端 API 的同步和/或異步行爲決定。Axis2 當前支持 WSDL 2.0 定義的 In-Only 和 In-Out MEP。Axis2 客戶端 API 支持服務的同步和異步調用。在調用 In-Out 操做時,在 API 級別和傳輸級別提供異步行爲。API 級別異步是經過回滾得到的,它使用一個傳輸鏈接來同時傳輸請求和響應(例如,經過一個 HTTP 鏈接傳輸請求和響應)。在傳輸級別異步中,使用不一樣的傳輸鏈接分別發送請求和接收響應,例如使用 SMTP 進行傳輸時即如此。
下面是使用 Axis2 客戶端 API 調用 In-Only 和 In-Out 操做的詳細信息。
調用 In-Only 操做
org.apache.axis2.clientapi.MessageSender 類用於調用 In-Only 操做(以下面的清單 3 所示),而 In-Only 操做調用 StockQuoteService 的 subscribe() 操做。
清單 3. 調用 In-Only 操做
try{ EndpointReference targetEPR = new EndpointReference( "http://localhost:8080/axis2/services/StockQuoteService"); // Make the request message OMFactory fac = OMAbstractFactory.getOMFactory(); OMNamespace omNs = fac.createOMNamespace( "http://www.developerworks.com/example", "example"); OMElement payload = fac.createOMElement("subscribe", omNs); payload.setText("IBM"); // Send the request MessageSender msgSender = new MessageSender(); msgSender.setTo(targetEPR); msgSender.setSenderTransport(Constants.TRANSPORT_HTTP); msgSender.send("subscribe", payload); }catch (AxisFault axisFault) { axisFault.printStackTrace(); }
MessageSender.send() 發送請求消息並將其當即返回。要使用的傳輸由 MessageSender.setSenderTransport() 指定。此示例經過 HTTP 發送消息。
調用 In-Out 操做
使用 org.apache.axis2.clientapi.Call 類能夠方便地調用 In-Out 操做。調用 In-Out 操做時,此 Call 類支持下列 4 種模式:
阻塞單傳輸模式:這是調用 In-Out Web 服務操做最簡單的方式。在操做完成和接收到響應或錯誤以前,服務調用被阻塞。它使用一個傳輸鏈接同時發送和接收響應,以下面的清單 4 所示。
清單 4. 阻塞單傳輸模式
try { EndpointReference targetEPR = new EndpointReference( "http://localhost:8080/axis2/services/StockQuoteService"); // Create request message OMFactory fac = OMAbstractFactory.getOMFactory(); OMNamespace omNs = fac.createOMNamespace( "http://www.developerworks.com/example", "example"); OMElement payload = fac.createOMElement("getQuote",omNs); payload.setText("IBM"); // Create the call Call call = new Call(); call.setTo(targetEPR); call.setTransportInfo(Constants.TRANSPORT_HTTP, Constants.TRANSPORT_HTTP, false); // Invoke blocking OMElement result = call.invokeBlocking("getQuote", payload); System.out.println("Quote ="+result.getText());}catch (AxisFault axisFault) { axisFault.printStackTrace();}
代碼的第一部分使用 AXIOM 建立請求消息。Call.setTransportInfo() 設置用於發送請求和得到響應的傳輸。Call.setTransportInfo() 操做的 Boolean 參數指出是否要使用不一樣的傳輸鏈接來分別發送請求和接收響應。在本例中,要求用一個 HTTP 鏈接發送請求和接收響應。
非阻塞單傳輸模式:在此調用模式中,只使用下面的一個傳輸鏈接得到非阻塞調用。若是在一個客戶端應用程序中要完成多個 Web 服務調用,並且不但願每次調用都阻塞客戶端,則須要此類行爲。此時,若是響應可用,則調用當即返回且客戶端得以回滾,以下面的清單 5 所示。
清單 5. 非阻塞單傳輸模式
try { EndpointReference targetEPR = new EndpointReference( "http://localhost:8080/axis2/services/StockQuoteService"); //Create the request OMFactory fac = OMAbstractFactory.getOMFactory(); OMNamespace omNs = fac.createOMNamespace( "http://www.developerworks.com/example", "example"); OMElement payload = fac.createOMElement("getQuote", omNs); payload.setText("IBM"); // Create the call Call call = new Call(); call.setTo(targetEPR); // Set the transport info. call.setTransportInfo(org.apache.axis2.Constants.TRANSPORT_HTTP, org.apache.axis2.Constants.TRANSPORT_HTTP, false); // Callback to handle the response Callback callback = new Callback() { public void onComplete(AsyncResult result) { System.out.println("Quote = " + result.getResponseEnvelope().getBody().getFirstElement() .getText()); } public void reportError(Exception e) { e.printStackTrace(); } }; // Invoke non blocking call.invokeNonBlocking("getQuote", payload, callback); //Wait till the callback receives the response. while (!callback.isComplete()) { Thread.sleep(1000); } call.close();} catch (AxisFault axisFault) { axisFault.printStackTrace();} catch (Exception ex) { ex.printStackTrace();}
Call.invokeNonBlocking() 方法當即返回而不阻塞。Call.invokeNonBlocking() 採用 org.apache.axis2.clientapi.CallBack 的對象,若是響應來自服務,則將觸發此對象。CallBack 有兩個抽象方法 onComplete(AsynchResult) 和 reportError(Exception),須要由具體的 CallBack 類實現這些方法。在服務調用正常完成後,Axis2 引擎調用 onComplete() 方法。在從服務器得到錯誤消息後,調用 Callback 的 reportError() 方法。Callback.isComplete() 將指出操做調用是否完成。
因 爲上面兩個方法使用一個傳輸鏈接來發送和接收消息,因此這些方法不適合長時間運行的事務。緣由是在響應可用以前,傳輸鏈接可能會超時。要解決此問題,可以使 用兩個不一樣的鏈接來分別發送請求和接收響應。但由於使用了其餘傳輸鏈接來得到響應,所以須要將請求和響應關聯起來。Axis2 支持 WS-Addressing,後者經過使用 <wsa:MessageID> 和 <wsa:RelatesTo> Header 可解決此問題。所以,若是使用兩個傳輸,則支持對模塊尋址,以下面兩個模式所示。
阻塞雙傳輸模式:此模式在如下狀況下很是有用:服務操做在本質上是 In-Out,但使用的傳輸是單向的(如 SMTP)或服務執行須要很長時間且 HTTP 鏈接超時。請參見下面的清單 6。
清單 6. 阻塞雙傳輸模式
try{ EndpointReference targetEPR = new EndpointReference( "http://localhost:8080/axis2/services/StockQuoteService"); OMFactory fac = OMAbstractFactory.getOMFactory(); OMNamespace omNs = fac.createOMNamespace( "http://www.developerworks.com/example", "example"); OMElement payload = fac.createOMElement("getQuote",omNs); payload.setText("IBM"); Call call = new Call(); call.setTo(targetEPR); call.setTransportInfo( Constants.TRANSPORT_HTTP, Constants.TRANSPORT_HTTP, true); //Blocking Invocation OMElement result = call.invokeBlocking("getQuote", payload); System.out.println("Quote = "+result.getText()); }catch (AxisFault axisFault) { axisFault.printStackTrace();}catch (Exception ex) { ex.printStackTrace();}
非阻塞雙傳輸模式:就 API 級別和傳輸級別的非阻塞而言,此模式提供了最大的靈活性,以下面的清單 7 所示。
清單 7. 非阻塞雙傳輸模式
try { EndpointReference targetEPR = new EndpointReference( "http://localhost:8080/axis2/services/StockQuoteService"); OMFactory fac = OMAbstractFactory.getOMFactory(); OMNamespace omNs = fac.createOMNamespace( "http://www.developerworks.com/example", "example"); OMElement payload = fac.createOMElement("getQuote",omNs); payload.setText("IBM"); Call call = new Call(); call.setTo(targetEPR); call.setTransportInfo( Constants.TRANSPORT_HTTP, Constants.TRANSPORT_HTTP, true); // Callback to handle the response Callback callback = new Callback() { public void onComplete(AsyncResult result) { System.out.println("Quote = " + result.getResponseEnvelope().getBody().getFirstElement() .getText()); } public void reportError(Exception e) { e.printStackTrace(); } }; // Non-Blocking Invocation call.invokeNonBlocking("getQuote", payload, callback); // Wait till the callback receives the response. while (!callback.isComplete()) { Thread.sleep(1000); } call.close(); }catch (AxisFault axisFault) { axisFault.printStackTrace();}catch (Exception ex) { ex.printStackTrace();}
回頁首
總結
在 這一由兩部分組成的系列的第 1 部分中,您瞭解了 Axis2 體系結構以及如何使用不一樣的調用模式來部署和使用一個簡單的 Web 服務。在本系列的第 2 部分中,您將詳細瞭解該體系結構,以及如何經過添加處理程序和 Axis2 消息接收器來自定義 Axis2。您還將瞭解如何使用 Axis2 提供的 XMLBeans 數據綁定支持。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/anyoneking/archive/2007/10/11/1819713.aspxweb