之前學習了同一服務中的session管理點擊打開鏈接,今天來看一下跨服務的session管理,本來昨天晚上把服務器端都寫好了,只剩下客戶端的代碼了,無奈,下班了,只好今天早上接着寫了,也好就當是複習了。
對於一個複雜的系統,不可能只有一個WebService服務,例如,至少會有一個管理用戶的WebService(用戶登錄和註冊)以及處理業務的WebService。象這種情況,就必須在多個WebService服務之間共享會話狀態,也稱爲跨服務會話(Session)管理。實現跨服務會話管理與實現同一個服務的會話管理的步驟類似,但仍然有一些差別,實現跨服務會話管理的步驟如下:
實現跨服務的Session管理需要如下三步:
1. 使用MessageContext和ServiceGroupContext獲得與設置key-value對。
2. 爲要進行Session管理的WebService類所對應的<service>元素添加一個scope屬性,並將該屬性值設爲application。
3. 在客戶端使用setManageSession(true)打開Session管理功能。
從上面的步驟可以看出,實現跨服務會話管理與實現同一個服務的會話管理在前兩步上存在着差異,而第3步是完全一樣的。下面是一個跨服務的會話管理的實例。在這個例子中有兩個WebService類:LoginService和SearchService,代碼如下:
- package crossSession;
- 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步:設置key-value對
- MessageContext mc = MessageContext.getCurrentMessageContext();
- ServiceGroupContext sgc = mc.getServiceGroupContext();
- sgc.setProperty("login", "成功登錄");
- return true;
- }
- else
- {
- return false;
- }
- }
- public String getLoginMsg()
- {
- // 第1步:獲得key-value對中的value
- MessageContext mc = MessageContext.getCurrentMessageContext();
- ServiceGroupContext sgc = mc.getServiceGroupContext();
- return (String)sgc.getProperty("login");
- }
- }
- package crossSession;
- import org.apache.axis2.context.MessageContext;
- import org.apache.axis2.context.ServiceGroupContext;
- public class SearchService
- {
- public String findByName(String name)
- {
- // 第1步:獲得key-value對中的value
- MessageContext mc = MessageContext.getCurrentMessageContext();
- ServiceGroupContext sgc = mc.getServiceGroupContext();
- if (sgc.getProperty("login") != null)
- return "找到的數據<" + name + ">";
- else
- return "用戶未登錄";
- }
- }
services.xml文件中的配置代碼如下:
- <serviceGroup>
- <!-- 第2步:添加scope屬性,並設置屬性值爲application -->
- <service name="loginSession" scope="application">
- <description>
- 登錄服務
- </description>
- <parameter name="ServiceClass">
- crossSession.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屬性,並設置屬性值爲application -->
- <service name="searchSession" scope="application">
- <description>
- 搜索服務
- </description>
- <parameter name="ServiceClass">
- crossSession.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步與點擊打開鏈接一文中介紹的方法類似。
下面是使用兩個stub類的對象實例訪問上面實現的兩個WebService的客戶端代碼:(由於是兩個service,所以要分別實現兩個stub類)
- package crossSession;
- import java.rmi.RemoteException;
- public class LoginSearchStubClient {
- public static void main(String[] args) throws RemoteException {
- // TODO Auto-generated method stub
- LoginSessionStub lss = new LoginSessionStub();
- LoginSessionStub.Login login = new LoginSessionStub.Login();
- LoginSessionStub.GetLoginMsg glm = new LoginSessionStub.GetLoginMsg();
- login.setUsername("bill");
- login.setPassword("1234");
- if(lss.login(login).local_return){
- System.out.println(lss.getLoginMsg(glm).get_return());
- SearchSessionStub sss = new SearchSessionStub();
- SearchSessionStub.FindByName fbn = new SearchSessionStub.FindByName();
- fbn.setName("bill");
- System.out.println(sss.findByName(fbn).local_return);
- }
- }
- }
在執行上面的代碼後,將輸出如下的信息:
如果將scope屬性值改成transportsession,我們看看會輸出什麼!
第一:改變loginService的
正常輸出,也就是說loginService這個服務只能在同一個服務中起作用,在這裏我們只是調用了登陸服務,所以沒影響。
第二:改變searchService的
居然還是正常輸出,不對啊,如下代碼需要跨服務的
- if (sgc.getProperty("login") != null)
- return "找到的數據<" + name + ">";
- else
- return "用戶未登錄";
這是怎麼回事呢,難道問題在這裏?
- // 第1步:獲得key-value對中的value
- MessageContext mc = MessageContext.getCurrentMessageContext();
- ServiceGroupContext sgc = mc.getServiceGroupContext(); //ServiceGroupContext而不是ServiceContext?
- //<span style="color:black;">ServiceGroupContext與scope衝突? </span>
好吧,既然衝突,那咱們就一個一個的試,結果更加出乎意料,把ServiceGroupContext改成ServiceContext,居然還是正常輸出,什麼情況?
這讓我開始懷疑這個程序是不是跨session的,不會是披着跨session的外衣吧,繼續研究!
先看一下scope中transportsession的問題,如下是官方文檔
</service>
看到這段話的時候我才感覺到transportsession不僅是單個服務那麼簡單的。
至於ServiceGroupContext和ServiceContext,我查了一下API文檔
可以看出來他們都是繼承自同一個類,而這個抽象類的setProperty()方法如下,
從這裏我們可以看到這個方法是用來存儲值的,至於存儲的值的訪問權限,我們只有搞清楚ServiceGroupContext和ServiceContext才能知道。
下面是ServiceContext的介紹
在這裏我們看到它的生命週期是不明確的,不推薦使用,而且其構造方法是可外部化的,關於這個問題,可以查看這篇文章點擊打開鏈接
下面是ServiceGroupContext的介紹
其實到這裏我還是沒多大明白ServiceGroupContext和ServiceContext的主要區別,於是我又看了MessageContext,結果又多了一個疑惑
爲什麼MessageContext只持有ServiceGroupContext,而沒有提及ServiceContext呢?
真是一波未平一波又起,看來還需要大家的智慧了,如果以上的這幾個問題有懂的高手,還請留言解決一下。