在 《WebService大講堂之Axis2(5):會(huì)話(huà)(Session)管理》 一文中介紹了如何使用Axis2來(lái)管理同一個(gè)服務(wù)的會(huì)話(huà),但對(duì)于一個(gè)復(fù)雜的系統(tǒng),不可能只有一個(gè)WebService服務(wù),例如,至少會(huì)有一個(gè)管理用戶(hù)的WebService(用戶(hù)登錄和注冊(cè))以及處理業(yè)務(wù)的WebService。象這種情況,就必須在多個(gè)WebService服務(wù)之間共享會(huì)話(huà)狀態(tài),也稱(chēng)為跨服務(wù)會(huì)話(huà)(Session)管理。實(shí)現(xiàn)跨服務(wù)會(huì)話(huà)管理與實(shí)現(xiàn)同一個(gè)服務(wù)的會(huì)話(huà)管理的步驟類(lèi)似,但仍然有一些差別,實(shí)現(xiàn)跨服務(wù)會(huì)話(huà)管理的步驟如下:
實(shí)現(xiàn)跨服務(wù)的Session管理需要如下三步:
1.?使用MessageContext和ServiceGroupContext獲得與設(shè)置key-value對(duì)。
2.?為要進(jìn)行Session管理的WebService類(lèi)所對(duì)應(yīng)的<service>元素添加一個(gè)scope屬性,并將該屬性值設(shè)為application。
3.?在客戶(hù)端使用setManageSession(true)打開(kāi)Session管理功能。
從上面的步驟可以看出,實(shí)現(xiàn)跨服務(wù)會(huì)話(huà)管理與實(shí)現(xiàn)同一個(gè)服務(wù)的會(huì)話(huà)管理在前兩步上存在著差異,而第3步是完全一樣的。下面是一個(gè)跨服務(wù)的會(huì)話(huà)管理的實(shí)例。在這個(gè)例子中有兩個(gè)WebService類(lèi):LoginService和SearchService,代碼如下:
LoginService.java
import ?org.apache.axis2.context.MessageContext;
import ?org.apache.axis2.context.ServiceGroupContext;
public ? class ?LoginService
{
???? public ? boolean ?login(String?username,?String?password)
????{????????
???????? if ( " bill " .equals(username)? && ? " 1234 " .equals(password))
????????{
???????????? // ??第1步:設(shè)置key-value對(duì)
????????????MessageContext?mc? = ?MessageContext.getCurrentMessageContext();
????????????ServiceGroupContext?sgc? = ?mc.getServiceGroupContext();
????????????sgc.setProperty( " login " ,? " 成功登錄 " );????
???????????? return ? true ;
????????}
???????? else
????????{
???????????? return ? false ;
????????}
????}????
???? public ?String?getLoginMsg()
????{
??????? // ??第1步:獲得key-value對(duì)中的value
????????MessageContext?mc? = ?MessageContext.getCurrentMessageContext();
????????ServiceGroupContext?sgc? = ??mc.getServiceGroupContext();
???????? return ?(String)sgc.getProperty( " login " );????
????}
}
SearchService.java
import ?org.apache.axis2.context.MessageContext;
import ?org.apache.axis2.context.ServiceGroupContext;
public ? class ?SearchService
{
???? public ?String?findByName(String?name)
????{
???????? // ??第1步:獲得key-value對(duì)中的value
????????MessageContext?mc? = ?MessageContext.getCurrentMessageContext();
????????ServiceGroupContext?sgc? = ??mc.getServiceGroupContext();????????????????
???????? if ?(sgc.getProperty( " login " )? != ? null )
???????????? return ? " 找到的數(shù)據(jù)< " ? + ?name? + ? " > " ;
???????? else
???????????? return ? " 用戶(hù)未登錄 " ;
????}
}
services.xml文件中的配置代碼如下:
???? <!-- ??第2步:添加scope屬性,并設(shè)置屬性值為application? -->
???? < service? name ="loginService" ?scope ="application" >
???????? < description >
????????????登錄服務(wù)
???????? </ description >
???????? < parameter? name ="ServiceClass" >
????????????service.LoginService
???????? </ parameter >
???????? < messageReceivers >
???????????? < messageReceiver? mep ="http://www.w3.org/2004/08/wsdl/in-out"
????????????????class ="org.apache.axis2.rpc.receivers.RPCMessageReceiver" ? />
???????? </ messageReceivers >
???? </ service >
???? <!-- ??第2步:添加scope屬性,并設(shè)置屬性值為application? -->
???? < service? name ="searchService" ?scope ="application" >
???????? < description >
????????????搜索服務(wù)
???????? </ description >
???????? < parameter? name ="ServiceClass" >
????????????service.SearchService
???????? </ parameter >
???????? < messageReceivers >
???????????? < messageReceiver? mep ="http://www.w3.org/2004/08/wsdl/in-out"
????????????????class ="org.apache.axis2.rpc.receivers.RPCMessageReceiver" ? />
???????? </ messageReceivers >
???? </ service >
</ serviceGroup >
第3步與《WebService大講堂之Axis2(5):會(huì)話(huà)(Session)管理》一文中介紹的方法類(lèi)似。
下面是使用兩個(gè)stub類(lèi)的對(duì)象實(shí)例訪(fǎng)問(wèn)上面實(shí)現(xiàn)的兩個(gè)WebService的客戶(hù)端代碼:
LoginServiceStub.Login?login? = ? new ?LoginServiceStub.Login();
login.setUsername( " bill " );
login.setPassword( " 1234 " );
if (stub.login(login).local_return)
{
????System.out.println(stub.getLoginMsg().local_return);
????SearchServiceStub?searchStub? = ? new ?SearchServiceStub();
????SearchServiceStub.FindByName?fbn? = ? new ?SearchServiceStub.FindByName();
????fbn.setName( " abc " );
????System.out.println(searchStub.findByName(fbn).local_return);?
}
在執(zhí)行上面的代碼后,將輸出如下的信息:
找到的數(shù)據(jù) < abc >
讀者可以將scope屬性值改成transportsession,看看會(huì)輸出什么!
??? 實(shí)際上,Axis2的會(huì)話(huà)管理也是通過(guò)Cookie實(shí)現(xiàn)的,與Web應(yīng)用中的Session管理類(lèi)似。如果讀者使用C#訪(fǎng)問(wèn)支持會(huì)話(huà)(在同一個(gè)服務(wù)中的會(huì)話(huà)管理)的WebService,需要指定一個(gè)CookieContainer對(duì)象,代碼如下:
System.Net.CookieContainer?cc? = ? new ?System.Net.CookieContainer();
ls.CookieContainer? = ?cc;
bool ?r,?rs;
ls.login( " bill " ,? " 1234 " ,? out ?@r,? out ?rs);
if ?(r)
{
????MessageBox.Show(ls.getLoginMsg().@return);
}
如果是訪(fǎng)問(wèn)跨服務(wù)的支持會(huì)話(huà)的WebService,則不需要指定CookieContainer對(duì)象,代碼如下:
bool?r,?rs;
ls.login("bill",?"1234",?out?@r,?out?rs);
if?(r)
{
????service1.searchService?ss?=?new?service1.searchService();
????MessageBox.Show(ss.findByName("abc"));
}
如果讀者使用delphi(本文使用的是delphi2009,其他的delphi版本請(qǐng)讀者自行測(cè)試)調(diào)用支持會(huì)話(huà)的WebService時(shí)有一些差別。經(jīng)筆者測(cè)試,使用delphi調(diào)用WebService,將scope屬性值設(shè)為transportsession和application都可以實(shí)現(xiàn)跨服務(wù)的會(huì)話(huà)管理,這一點(diǎn)和Java與C#不同,Java和C#必須將scope屬性值設(shè)為application才支持跨服務(wù)會(huì)話(huà)管理。在delphi中不需要象C#指定一個(gè)CookieContainer或其他類(lèi)似的對(duì)象,而只需要象訪(fǎng)問(wèn)普通的WebService一樣訪(fǎng)問(wèn)支持會(huì)話(huà)的WebService即可。