作者:李紅霞
時間:2006-10-19
聲明:本文可以算作Axis2用戶手冊的翻譯,但是翻譯后的文本是經過作者理解寫出來的,可能有些偏差,歡迎討論。本文屬作者原創,允許轉載,但請注明出處。
英文原文http://ws.apache.org/axis2/1_0/userguide.html
?
概述
這個說明文檔涉及以下內容:
????
如何使用
axis2
創建
web service
和客戶端程序
????
如何定制一個模塊
(Module)
并在
web service
中使用它
????
Samples discussion
????
Advanced Topics
?
第一部分:簡介
?
Axis2
是重新設計的一個架構,它沒有基于
Axis1.*
的結構,這種新的架構
much more flexible, efficient and configurable
。
?
Axis2
的特性有:
Speed
??????????????????????????????????????????? ??
采用自己的對象模型,利用
StAX
解析
Low memory foot print
?????????????????? Axis2
在設計過程中一直遵循
low memory cost
的理念
AXIOM
???????????????????????????????????????? ??
采用自己的輕量級的對象模型,使得消息處理過程可擴展、性能高,對開發者來說更加簡單。
Hot Deployment
??????????????????????????? ?Axis2
裝備了在系統運行時部署服務和處理器的能力。也就是說,新的服務新服務的添加不再需要重啟服務器。將服務的發布包放在服務部屬文件夾中,部署模型將自動部署該服務。
Asynchronous Web Services
???????? Axis2
現在可以通過
non-blocking clients and transports
支持異步的服務和異步的服務調用。(?什么是異步的服務
?
)
MEP Support
??????????????????????????????? ? Axis2
具備良好的伸縮性來支持
MEPs
,因為它內置了對
WSDL2.0
中
MEPs
的支持。
Flexibility
?????????????????????????????????????? ? Axis2
的架構使得程序員能自由的對
Axis
添加擴展,這些擴展包括對自定義
Header
的處理,系統管理,甚至是任何一件你可以想象的到的事情
Stability
?????????????????????????????????????????? ?Axis2
定義了一套公共接口,這些接口相對于其他代碼而言改動很小
Component-oriented Deployment
??
你可以自定義一些在處理過程中常用的可重用的處理器,并可以將這些處理器發布出來供其它人使用
Transport Framework
?????????????????????
定義了一個干凈、簡單的抽象作品來集成任意的傳輸協議,引擎的核心部分的實現是與傳輸協議無關的
Add-ons
?????????????????????????????????????????????
一些
web service
相關的協議也合并了進來。如安全方面的
WSS4J(Rampart),
可靠消息傳輸的
Sandesha
,封裝了
WS-Coordination, WS-AtomicTransaction
和
WS-BusinessActivity
的
Kandula
。
Composition and Extensibility
????????
模塊和層支持可擴展性和可組合性(
composability
)。模塊支持可組合性,對添加新的
web service
規范的支持的方式非常簡單和干凈。但是他們并不是熱部署的,因為他們影響整個系統的功能。
?
Tips:
WSS4J: http://ws.apache.org/wss4j/
Apache WSS4J is an implementation of the OASIS Web Services Security (WS-Security) from OASIS Web Services Security TC. WSS4J is a primarily a Java library that can be used to sign and verify SOAP Messages with WS-Security information. WSS4J will use Apache Axis and Apache XML-Security projects and will be interoperable with JAX-RPC based server/clients and .NET server/clients.
這個項目提供了在
Axis
上部署的幫助文檔和例子
Rampart
這是
Axis2
的一個
Module
(現在
Axis2
有兩個可選的
Module
,分別是
Addressing
和
Security
,
Addressing
包含在
Standard
版本中,但是
Rampart
需要單獨下載),目前作用不詳,猜測是與
WSS4J
合作完成
WS-Security
Sendesha: http://ws.apache.org/sandesha/
Sandesha2 is an implementation of WS-ReliableMessaging specification published by IBM, Microsoft, BEA and TIBCO. Sandesha2 was built on top of Axis2. Therefore by using Sandesha2 you can add reliable messaging capability to the web services hosted using Axis2. Sandesha2 can also be used with Axis2 client to interact with already hosted web services in a reliable manner. Please see sandesha2 user guide for more information on using Sandesha2.
Kandula: http://ws.apache.org/kandula/2/index.html
Kandula will provide an open-source implementation of WS-Coordination, WS-AtomicTransaction and WS-BusinessActivity based on Axis. The initial implementation will be in Java using Axis/Java. In addition to providing an implementation, a major focus of this project would be to ensure interoperability with other implementations of above specifications, particularly those by Microsoft (.NET) and IBM.
?
第二部分:使用
Axis2
開發
web services
首先你需要在
Servlet
容器中部署
axis2.war
?
可以通過兩種方式來創建
web services
?
1.??????
使用
Axis2
的
API
,實現業務代碼
2.??????
從
WSDL
開始,生成代碼框架,然后實現業務邏輯
?
1
)使用
Axis2
的
API
首先,計劃生成一個服務
MyService
,它有兩個方法:
public void ping(OMElement element){} //IN-ONLY operation, just accepts the OMElement and do some processing.
public OMElement echo(OMElement element){}//IN-OUT operation, accepts an OMElement and?
????????????????????????????????????????? // sends back the same again
從例子里找到實現的代碼:
"Axis2Home/samples/userguide/src"
中的
"userguide/example1"
?
創建一個服務分
4
個步驟
a.??????
編寫實現代碼
b.??????
用
service.xml
來解釋這個服務
c.??????
創建一個
*.aar
的服務部署包
d.??????
發布服務
?
Step 1:
實現代碼
public class MyService{
??? public void ping(OMElement element){
???? ......
??? }
??? public OMElement echo(OMElement element){
???? ......
??? }
}
?
Step 2:
通過
service.xml
來描述服務
<service >
??? <description>
??????? This is a sample Web Service with two operations, echo and ping.
??? </description>
??? <parameter name="ServiceClass" locked="false">userguide.example1.MyService</parameter>
??? <operation name="echo">
??????? <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
??????? <actionMapping>urn:echo</actionMapping>
??? </operation>
???? <operation name="ping">
??????? <messageReceiver class="org.apache.axis2.receivers.RawXMLINOnlyMessageReceiver"/>
??????? <actionMapping>urn:ping</actionMapping>
??? </operation>
?</service>
?
說明:
For the "echo" operation we have used a RawXMLINOutMessageReceiver since it is an IN-OUT operation. For IN-ONLY operation "ping", we have used RawXMLINOnlyMessageReceiver as the message receiver.
The actionMapping is required only if you want to enable WS-Addressing.
?
還可以用這個文件來描述一組服務,這組服務之間可以共享
ServiceGroupContext
<serviceGroup>
? <service name="Service1">
??? <!-- details for Service1 -->
? </service>
? <service name="Service2">
??? <!-- details for Service2 -->
? </service>
? <module ref="ModuleName" />
? <parameter name="serviceGroupParam1" locked="false">value 1</parameter>
</serviceGroup>
?
?
Step 3:
創建服務發布包
這個服務發布包的結構如圖所示。將這些文件按照圖中的結構組織好,然后打包成
jar
或者
rar
,然后修改后綴名為
aar
即可。
?
Step 4:
部屬服務
將服務發布包放到
"\webapps\axis2\WEB-INF"
中的
"services"
文件夾下,然后在
Axis2
的首頁
(http://localhost:8080/axis2/index.jsp)
的
’services’
連接下察看服務發布情況
?
?
?
2
)用服務代碼生成的方式創建服務
首先要寫好服務的
wsdl
?
然后利用
WSDL2Java
工具
該工具的命令有:
Usage WSDL2Code -uri <Location of WSDL> : WSDL file location
-o <output Location> : output file location
-a : Generate async style code only. Default is off
-s : Generate sync style code only. Default is off. takes precedence over -a
-p <package name> : set custom package name
-l <language> : valid languages are java and csharp. Default is java
-t : Generate TestCase to test the generated code
-ss : Generate server side code (i.e. skeletons). Default is off
-sd : Generate service descriptor (i.e. services.xml). Default is off. Valid with -ss
-d <databinding> : valid databinding(s) are adb, xmlbeans and jaxme. Default is adb
-g Generates all the classes. valid only with the -ss
-pn <port_name> : name of port in the presence of multiple ports
-sn <service_name> : name of service in the presence of multiple services
-u : unpacks the databinding classes
-r <repository_path> : path of the repository against which code is generated
?
在
windows
平臺下可以用
WSDL2Java -uri ..\samples\wsdl\Axis2SampleDocLit.wsdl -ss -sd -d xmlbeans -o ..\samples -p org.apache.axis2.userguide
?
在
Linux
平臺下可以用
WSDL2Java -uri ../samples/wsdl/Axis2SampleDocLit.wsdl -ss -sd -d xmlbeans -o ../samples -p org.apache.axis2.userguide
于是生成了服務的代碼框架,在代碼框架中填入代碼
?
第三部分:用
Axis2
創建服務客戶端
服務可以完成各種各樣的功能,有的簡單,時間消費比較低,有的復雜,時間消費比較高。我們不能采用一個統一的機制來調用這些時間消費區別很大的服務。例如:我們用
HTTP
協議來帶調用一個
IN-OUT
類型的服務,而這個服務的執行時間很長,于是我們可能得到一個
connection time out
的結果。而且,在一個客戶端同時發出兩個服務調用請求的情況下,使用
’blocking’
的客戶端
API
將降低客戶端程序的性能。類似的,當我們使用
One-Way
傳輸的時候還可能有很多其他的后果產生。
?
Blocking API:???????????
當服務調用請求發出后,客戶端等待服務結果的返回,這期間不能再發出服務調用請求。
Non-Blocking API:???
這是一個基于
callback
或者
polling
的
API
,讓客戶端發出服務調用請求的時候,客戶端程序立刻得到控制權,服務的調用結果由
callback
對象來接收。這樣,客戶端就可以同時調用多個服務而不進行阻止。
?
Axis
將利用
Non-Blocking API
方式的異步叫做
API Level Asynchrony
?
前面提到的兩個機制在
Request
和
Response
上使用了一個的傳輸連接,他們限制了服務調用在請求與結果返回使用兩個傳輸連接的情況
(
either One-Way or Two-Way
)
。所以這兩種機制都無法解決在長時間運行的事務中的尋址問題(傳輸連接可能在操作結束前就已經
timeout
了)。一種解決方案是在
request
和
response
中使用兩個不同的傳輸連接。
?
在這個級別上得到的異步屬性,稱為
Transport Level Asynchrony
?
將前面的
2
種異步結合起來,就有了四種不同的調用模式
API (Blocking/Non-Blocking)
|
?Dual Transports (Yes/No)
|
Description
|
Blocking
|
No
|
Simplest and the familiar invocation pattern
|
Non-Blocking
|
No
|
Using callbacks or polling
|
Blocking
|
Yes
|
This is useful when the service operation is IN-OUT in nature but the transport used is One-Way (e.g. SMTP)
|
Non-Blocking
|
Yes
|
This is can be used to gain the maximum asynchronous behavior. No blocking in the API level and also in the transport level
|
?
服務的調用代碼:
blocking invocation
try {
OMElement payload = ClientUtil.getEchoOMElement();
Options options = new Options();
options.setTo(targetEPR); // this sets the location of MyService service
ServiceClient serviceClient = new ServiceClient();
serviceClient.setOptions(options);
OMElement result = sender.sendReceive(payload);
System.out.println(result);
} catch (AxisFault axisFault) {
axisFault.printStackTrace();
}
?
IN-ONLY
try {
OMElement payload = ClientUtil.getPingOMElement();
Options options = new Options();
options.setTo(targetEPR);
ServiceClient serviceClient = new ServiceClient();
serviceClient.setOptions(options);
serviceClient.fireAndForget(payload);
/**We have to block this thread untill we send the request , the problemis if we go out of the
*main thread , then request wont send ,so you have to wait some time :) */
Thread.sleep(500);
} catch (AxisFault axisFault) {
axisFault.printStackTrace();
}
?
You can test this client by running the target "testPingClient" of the ant build file at "Axis2Home/samples/userguide".
?
EchoBlockingClient
將第一段代碼的調用代碼改為
serviceClient.sendReceiveNonblocking(payload, callback);
具體的例子在
"Axis2Home/samples/userguide/src/userguide/clients"
中
Axis
提供三個方法來接收
callback
對象
public abstract void onComplete(AsyncResult result);
public abstract void onError(Exception e);
public boolean isComplete() {}
其中,前面兩個是需要用戶來實現的
?
EchoNonBlockingDualClient
try {
OMElement payload = ClientUtil.getEchoOMElement();
Options options = new Options();
options.setTo(targetEPR);
options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
options.setUseSeparateListener(true);
options.setAction("urn:echo");? // this is the action mapping we put within the service.xml
//Callback to handle the response
Callback callback = new Callback() {
public void onComplete(AsyncResult result) {
System.out.println(result.getResponseEnvelope());
}
public void onError(Exception e) {
e.printStackTrace();
}
};
//Non-Blocking Invocation
sender = new ServiceClient();
sender.engageModule(new QName(Constants.MODULE_ADDRESSING));
sender.setOptions(options);
sender.sendReceiveNonBlocking(payload, callback);
//Wait till the callback receives the response.
while (!callback.isComplete()) {
Thread.sleep(1000);
}
//Need to close the Client Side Listener.
} catch (AxisFault axisFault) {
axisFault.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
sender.finalizeInvoke();
} catch (AxisFault axisFault) {
//have to ignore this
}
}
?
在
Server
端添加
Addressing
支持的方式是,在
Addressing Module
中,將
Handlers
的描述放在
”pre-dispatch”
語句中,那么它的加載則需要通過在
"/webapps/axis2/WEB-INF"
文件夾下的
axis2.xml
中增加一句話來完成:
<module ref="addressing"/>
?
客戶端支持
Addressing
的方式,一種是將
addressing-<version>.mar
放在
classpath
中,另一種就是根據給定的庫位置創建一個
ConfigurationContext
具體的做法是在
sender = new ServiceClient();
之前加上
ConfigurationContext configContext = ConfigurationContextFactory.createConfigurationContextFromFileSystem(< Axis2RepositoryLocation >, null);
然后將
"sender = new ServiceClient();"
改為
"sender = new ServiceClient(configContext, null);"
?
EchoBlockingDualClient
示例代碼可以在
"Axis2Home/samples/userguide/src/userguide/clients/"
中找到,它與
EchoNonBlockingDualClient
相似,在這種情況下不再需要
callback
來處理
response
。這個機制非常適用于處理
IN-OUT
類型的調用,而傳輸協議卻是
One-Way(SMTP)
的情況。我們可以用
"Axis2Home/samples/userguide"
中的
"echoBlockingDualClient"
來測試
?
第四部分:
Module
構造和部署
Module
分為以下幾個步驟:
a.??????
創建
Module
的實現
b.??????
創建
Handlers
c.??????
創建
module.xml
d.??????
修改
axis2.xml
(如果你需要定制的語句)
e.??????
修改
services.xml
在
Axis
部署的時候使用這些
Modules
f.???????
在
Axis2
中部署這些
Modules
?
現在來創建一個簡單的
Logging Module
,這個
Module
包含一個
Hander
,它的作用就是紀錄通過它的消息。
Axis
通過
*.mar
來部署
Modules
,下圖就是這個部署包的結構
Step 1:
創建
LoggingModule Class
Logging Module
是
Axis2 Module
的實現,它必須實現
org.apache.axis2.modules.Module
接口:
?
Step 2:
創建
LogHandler
Axis
的一個
Module
可以包含一個或者多個
Handler
。這些
Handler
將處理
Soap
頭文件中的不同
phases
。一個
Handler
必須實現
org.apache.axis2.engine.Handler
接口,或者通過另一種簡單方式,繼承
org.apache.axis2.handlers.AbstractHandler
類
public class LogHandler extends AbstractHandler implements Handler {
private Log log = LogFactory.getLog(getClass());
??? private QName name;
public QName getName() {
??????? return name;
??? }
??? public void invoke(MessageContext msgContext) throws AxisFault {
??????? log.info(msgContext.getEnvelope().toString());
??? }
??? public void setName(QName name) {
??????? this.name = name;
??? }
}
?
Step 3: module.xml
這個文件包含了一個特定
Module
的部署配置。
<module name="logging" class="userguide.loggingmodule.LoggingModule ">
?? <inflow>
??????? <handler name="InFlowLogHandler" class="userguide.loggingmodule.LogHandler">
??????? <order phase="loggingPhase" />
??????? </handler>
?? </inflow>
?? <outflow>
??????? <handler name="OutFlowLogHandler" class="userguide.loggingmodule.LogHandler">
??????? <order phase="loggingPhase"/>
??????? </handler>
?? </outflow>
?? <Outfaultflow>
??????? <handler name="FaultOutFlowLogHandler" class="userguide.loggingmodule.LogHandler">
??????? <order phase="loggingPhase"/>
??????? </handler>
?? </Outfaultflow>
?? <INfaultflow>
??????? <handler name="FaultInFlowLogHandler" class="userguide.loggingmodule.LogHandler">
??????? <order phase="loggingPhase"/>
??????? </handler>
?? </INfaultflow>
</module>
?
a.??????
inflow?- Represents the handler chain that will run when a message is coming in.
b.??????
outflow?- Represents the handler chain that will run when the message is going out.
c.??????
Outfaultflow - Represents the handler chain that will run when there is a fault and the fault is going out
d.??????
INfaultflow?- Represents the handler chain that will run when there is a fault and the fault is coming in
?
"<order phase="loggingPhase" />" describes the phase in which this handler runs.
?
Step 4:
修改
axis2.xml
在前面用的
”loggingPhase”
不是一個
pre-defined handler phase
,因此,
module
的創建者需要將它介紹給
axis2.xml
于是
Axis
引擎就可以知道在不同的
’flow’
中如何放那些
handlers
。
這些增加是在
axis2.xml
的
Phases
部分,在標志了
<!--????? user can add his own phases to this area? -->
之后加入
<phase name=" loggingPhase"/>
這樣,這個
phase
將在引擎的任何消息流中調用
?
Step 5:
修改
service.xml
到目前為止,
logging module
已經做好了,現在需要在服務中使用這個
module
,那么就要修改服務的
service.xml
。在該文件中加上了
"<module ref="logging"/>"
?
Step 6:
打包
將這個包打成
jar
或者
rar
,然后改后綴名為
mar
。
?
Step 7:
在
Axis2
中部署這個
Module
首先要在
"webapps/axis2/WEB-INF"
目錄下創建一個
modules
文件夾,然后將
*.mar
文件放在這個文件夾中,然后重啟
Axis
并運行服務進行測試
?
第五部分:其他的例子
有
Google Spell Checker, Google Search,
和
Amazon Queuing Service
的例子
?