Axis2 是下一代 Apache Axis。Axis2 雖然由 Axis 1.x 處理程序模型提供支持,但它具有更強的靈活性并可擴展到新的體系結(jié)構(gòu)。Axis2 基于新的體系結(jié)構(gòu)進行了全新編寫,而且沒有采用 Axis 1.x 的常用代碼。支持開發(fā) Axis2 的動力是探尋模塊化更強、靈活性更高和更有效的體系結(jié)構(gòu),這種體系結(jié)構(gòu)可以很容易地插入到其他相關(guān) Web 服務(wù)標準和協(xié)議(如 WS-Security、WS-ReliableMessaging 等)的實現(xiàn)中。
Axis2 的特性包括:
- 采用名為 AXIOM(AXIs Object Model,Axis 對象模型)的新核心 XML 處理模型
- 支持 In-Only 和 In-Out 消息交換模式 (MEP)
- 阻塞和非阻塞客戶端 API(應(yīng)用程序編程接口)
- 支持內(nèi)置的 Web 服務(wù)尋址 (WS-Addressing)
- 支持 XMLBeans 數(shù)據(jù)綁定
- 新部署模型
- 支持超文本傳輸協(xié)議 (HTTP)、簡單郵件傳輸協(xié)議 (SMTP) 和傳輸控制協(xié)議 (TCP) 等傳輸協(xié)議
本系列文章以 Axis2 0.92 版本為基礎(chǔ)。您可以在 Apache 網(wǎng)站獲得 Axis2 的最新版本。
![]() ![]() |
![]()
|
圖 1. Axis2 體系結(jié)構(gòu)

Axis2 體系結(jié)構(gòu)將邏輯與狀態(tài)分離;這允許在并行線程中執(zhí)行邏輯。服務(wù)和調(diào)用的靜態(tài)狀態(tài)和動態(tài)狀態(tài)分別存儲在 Description
和 Context
類中。Axis2 體系結(jié)構(gòu)是使用 7 個獨立模塊實現(xiàn)的。
-
信息模型:此模塊管理 SOAP 引擎的狀態(tài)。該模型定義一組用于存放狀態(tài)的類,而引擎管理這些信息對象的生命周期。信息模型包含兩種用于存放狀態(tài)的類。
Description
類存放本質(zhì)上是靜態(tài)的且存在于 Axis 引擎實例的整個生命周期中的數(shù)據(jù)(如傳輸、服務(wù)和操作的配置)。Context
類存放調(diào)用上下文中有效的服務(wù)和操作的動態(tài)信息,例如當(dāng)前請求和響應(yīng) SOAP 消息、From 地址、To 地址和其他元素。 - XML 處理模型:Axis2 引入了一個名為 AXIOM 的新模型,用于處理 SOAP 消息。AXIOM 使用 StAX (Streaming API for XML) 來解析 XML。StAX 是一個標準的流式 Pull 解析器 Java™ API。AXIOM 非常精巧,不會減慢 XML 信息集的構(gòu)建速度——換句話說,對象只有在絕對必要時才會創(chuàng)建。總體而言,AXIOM 和 Axis2 所占用的內(nèi)存要小于 Axis 1 所占用的內(nèi)存。
-
SOAP 處理模型:Axis2
體系結(jié)構(gòu)定義了兩個管道(或流),分別稱為 InPipe (InFlow) 和 OutPipe
(OutFlow),用于處理服務(wù)器端的請求消息和響應(yīng)消息。在客戶端,這兩個管道是反向的——換句話說,SOAP 請求消息流經(jīng)
OutPipe,而響應(yīng)消息流經(jīng) InPipe。管道或流包含一系列分為階段的處理程序。階段按照預(yù)先定義的順序執(zhí)行,如上面的圖 1 所示。除預(yù)先定義的階段和處理程序集外,用戶還可以在操作級別、服務(wù)級別或全局級別配置用戶階段和相關(guān)處理程序。處理程序充當(dāng) SOAP 消息的攔截器,可以處理 SOAP 消息的 Header 或 Body。InPipe 是通過以下階段進行配置的:
- TransportIn
- PreDispatch
- Dispatch
- PostDispatch
- PolicyDetermination
- User phases
- Message validation
- Message initialization
- Policy determination
- User phases
- MessageOut
-
部署模塊:此模塊配置 Axis 引擎并部署服務(wù)和模塊。axis2.xml(在 webapps/axis2/WEB-INF 中)包含 Axis2 引擎的全局配置,包括:
- 全局模塊 (Global modules)
- 全局接收器 (Global receivers)
- 傳輸 (Transports)
- 用戶階段定義 (User phase definitions)
- WSDL 和代碼生成:此模塊從 WSDL 文件中生成客戶端存根和服務(wù)器框架代碼。Axis2 代碼生成器發(fā)出采用正確 XML 樣式表的 XML 文件,以用所需語言生成代碼。
- 客戶端 API:Axis2 客戶端 API 調(diào)用遵循 WSDL 2.0 定義的 In-Only 和 In-Out 消息模式的操作。客戶端 API 支持 In-Out 操作的阻塞和非阻塞調(diào)用。
- 傳輸:此模塊包含與傳輸層交互的處理程序。傳輸處理程序有兩種類型:TransportListener 和 TransportSender。TransportListener 從傳輸層接收 SOAP 消息,然后將其傳送到 InPipe 進行處理。TransportSender 發(fā)送通過指定傳輸從 OutPipe 接收到的 SOAP 消息。Axis2 提供 HTTP、SMTP 和 TCP 的處理程序。對于 HTTP 傳輸,服務(wù)器端上的 AxisServlet 和客戶端上的一個簡單的獨立 HTTP 服務(wù)器(由 Axis2 提供)充當(dāng) TransportReceiver。
![]() ![]() |
![]()
|
部署 Axis2 與部署 Axis 1 一樣簡單。首先在 Axis2 二進制代碼分發(fā)包的 webapps 目錄下查找 Axis2 Web 應(yīng)用程序 axis2.war。在 servlet 容器中部署此 war 文件。在 Tomcat 中,如果已在服務(wù)器配置中將 unpackWARs 設(shè)置為 True,則只需將 axis2.war 復(fù)制到 $TOMCAT_HOME/webapps 目錄即可部署 Axis2。請立即啟動 Tomcat 并訪問 http://localhost:<port>/axis2。將顯示 Axis2 歡迎頁,單擊此頁上的 Validate 鏈接。您應(yīng)到達 Axis2 Happiness page,不會出現(xiàn)任何錯誤。
![]() ![]() |
![]()
|
下 面介紹如何使用 In-Only subscribe() 和 In-Out getQuote() 這兩個操作來開發(fā) StockQuoteService。subscribe() 操作將預(yù)訂指定代號的每小時報價,而 getQuote() 將獲得指定代號的當(dāng)前報價。
下面的清單 1 是 StockQuoteService 的實現(xiàn)示例:
清單 1. StockQuoteService 實現(xiàn)
|
對方法簽名感到很疑惑?我們將討論上述方法中的 OMElement。
![]() ![]() |
![]()
|
部署描述符
在 Axis2 中,服務(wù)部署信息包含在 services.xml 文件(在 0.92 以前的版本中,此文件名為 service.xml)中。對于上述 StockQuoteService,服務(wù)部署描述符與下面的清單 2 類似。
清單 2. Services.xml
|
服務(wù)的 name
屬性定義服務(wù)的名稱。Axis2 使用服務(wù)的名稱創(chuàng)建服務(wù)的端點地址,例如
http://localhost:<port>/axis2/services/<nameofservice>。因此,對于
StockQuoteService,服務(wù)端點為 http://localhost:<port>/axis2/services/StockQuoteService。ServiceClass
參數(shù)指定服務(wù)實現(xiàn)類。
每個 <operation> 元素定義服務(wù)中一個操作的配置。<operation> 的 name 屬性應(yīng)設(shè)置為服務(wù)實現(xiàn)類中方法的名稱。messageReceiver
元素定義用于處理此操作的消息接收器。Axis2 針對 In-Only 和 In-Out 操作提供了兩個無數(shù)據(jù)綁定的內(nèi)置 MessageReceivers;org.apache.axis2.receivers.RawXMLINOnlyMessageReceiver
用于 In-Only 操作,而 org.apache.axis2.receivers.RawXMLINOutMessageReceiver
用于 In-Out 操作。如果沒有指定 messageReceiver,則 Axis2 將嘗試使用
org.apache.axis2.receivers.RawXMLINOutMessageReceiver 作為缺省的
messageReceiver。上述 RAWXML 消息接收器將傳入 SOAP 消息的 <Body> 的內(nèi)容作為
OMElement(OMElement 是 XML 元素的 AXIOM 縮寫)傳遞給服務(wù)實現(xiàn)。此操作應(yīng)作為 OMElement 返回 SOAP
響應(yīng)的 <Body> 元素包含的 XML 內(nèi)容。這便解釋了為何 subscribe() 和 getQuote() 操作采用和返回
OMElement。
services.xml 還可以包含分為 servicegroup 的多個服務(wù)。
打包
Axis 2 服務(wù)是作為 Axis Archive (.aar) 打包的。這是一個 JAR 文件(使用 jar 或 zip 實用程序創(chuàng)建),在存檔的 META-INF 目錄中打包了 services.xml 文件。StockQuoteService 在打包成 StockQuoteService.aar 時將具有以下結(jié)構(gòu):
./stock/StockQuoteService.class |
預(yù)先打包的 StockQuoteService 存檔可以在本文的下載部分中找到。
部署
在 Axis2 中部署服務(wù)相當(dāng)簡單,只需將 .aar 文件復(fù)制到 servlet 容器的 axis2 Web 應(yīng)用程序中的 axis2/WEB-INF/services 目錄下即可。對于 Tomcat,此位置為 $TOMCAT_HOME/webapps/axis2/WEB-INF/services。
另一種部署服務(wù)的好方法是使用 Axis2 管理控制臺中的 Upload Service 工具。請轉(zhuǎn)到 http://localhost:<port>/axis2,然后選擇 Administration 鏈接。輸入用戶名和密碼 admin/axis2,然后登錄。(您可以在 axis2.xml 中配置用戶名/密碼。)在工具部分選擇 Upload Service 鏈接,再選擇 .aar 文件,然后單擊 Upload。就是這樣簡單!如果上傳成功,系統(tǒng)將顯示一條綠色成功消息。服務(wù)即被部署,而且可隨時調(diào)用。如果要在遠程 Axis2 服務(wù)器上部署服務(wù),則此功能非常方便。
![]() ![]() |
![]()
|
Web 服務(wù)調(diào)用的特性由 MEP、傳輸協(xié)議以及客戶端 API 的同步和/或異步行為決定。Axis2 當(dāng)前支持 WSDL 2.0 定義的 In-Only 和 In-Out MEP。Axis2 客戶端 API 支持服務(wù)的同步和異步調(diào)用。在調(diào)用 In-Out 操作時,在 API 級別和傳輸級別提供異步行為。API 級別異步是通過回滾獲得的,它使用一個傳輸連接來同時傳輸請求和響應(yīng)(例如,通過一個 HTTP 連接傳輸請求和響應(yīng))。在傳輸級別異步中,使用不同的傳輸連接分別發(fā)送請求和接收響應(yīng),例如使用 SMTP 進行傳輸時即如此。
下面是使用 Axis2 客戶端 API 調(diào)用 In-Only 和 In-Out 操作的詳細信息。
org.apache.axis2.clientapi.MessageSender
類用于調(diào)用 In-Only 操作(如下面的清單 3 所示),而 In-Only 操作調(diào)用 StockQuoteService
的 subscribe()
操作。
清單 3. 調(diào)用 In-Only 操作
|
MessageSender.send()
發(fā)送請求消息并將其立即返回。要使用的傳輸由 MessageSender.setSenderTransport()
指定。此示例通過 HTTP 發(fā)送消息。
使用 org.apache.axis2.clientapi.Call
類可以方便地調(diào)用 In-Out 操作。調(diào)用 In-Out 操作時,此 Call
類支持下列 4 種模式:
-
阻塞單傳輸模式:這是調(diào)用 In-Out Web 服務(wù)操作最簡單的方式。在操作完成和接收到響應(yīng)或錯誤之前,服務(wù)調(diào)用被阻塞。它使用一個傳輸連接同時發(fā)送和接收響應(yīng),如下面的清單 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 創(chuàng)建請求消息。
Call.setTransportInfo()
設(shè)置用于發(fā)送請求和獲得響應(yīng)的傳輸。Call.setTransportInfo()
操作的 Boolean 參數(shù)指出是否要使用不同的傳輸連接來分別發(fā)送請求和接收響應(yīng)。在本例中,要求用一個 HTTP 連接發(fā)送請求和接收響應(yīng)。 -
非阻塞單傳輸模式:在此調(diào)用模式中,只使用下面的一個傳輸連接獲得非阻塞調(diào)用。如果在一個客戶端應(yīng)用程序中要完成多個 Web 服務(wù)調(diào)用,而且不希望每次調(diào)用都阻塞客戶端,則需要此類行為。此時,如果響應(yīng)可用,則調(diào)用立即返回且客戶端得以回滾,如下面的清單 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
的對象,如果響應(yīng)來自服務(wù),則將觸發(fā)此對象。CallBack
有兩個抽象方法onComplete(AsynchResult)
和reportError(Exception)
,需要由具體的CallBack
類實現(xiàn)這些方法。在服務(wù)調(diào)用正常完成后,Axis2 引擎調(diào)用onComplete()
方法。在從服務(wù)器獲得錯誤消息后,調(diào)用Callback
的reportError()
方法。Callback.isComplete()
將指出操作調(diào)用是否完成。因 為上面兩個方法使用一個傳輸連接來發(fā)送和接收消息,所以這些方法不適合長時間運行的事務(wù)。原因是在響應(yīng)可用之前,傳輸連接可能會超時。要解決此問題,可使 用兩個不同的連接來分別發(fā)送請求和接收響應(yīng)。但因為使用了其他傳輸連接來獲得響應(yīng),因此需要將請求和響應(yīng)關(guān)聯(lián)起來。Axis2 支持 WS-Addressing,后者通過使用 <wsa:MessageID> 和 <wsa:RelatesTo> Header 可解決此問題。因此,如果使用兩個傳輸,則支持對模塊尋址,如下面兩個模式所示。
-
阻塞雙傳輸模式:此模式在以下情況下非常有用:服務(wù)操作在本質(zhì)上是 In-Out,但使用的傳輸是單向的(如 SMTP)或服務(wù)執(zhí)行需要很長時間且 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 體系結(jié)構(gòu)以及如何使用不同的調(diào)用模式來部署和使用一個簡單的 Web 服務(wù)。在本系列的第 2 部分中,您將詳細了解該體系結(jié)構(gòu),以及如何通過添加處理程序和 Axis2 消息接收器來自定義 Axis2。您還將了解如何使用 Axis2 提供的 XMLBeans 數(shù)據(jù)綁定支持。