Session詳解(2)

 

五、理解javax.servlet.http.HttpSession
HttpSession是Java平臺對session機制的實現規範,因爲它僅僅是個接口,具體到每個web應用服務器的提供商,除了對規範支持之外,仍然會有一些規範裏沒有規定的細微差異。這裏我們以BEA的Weblogic Server8.1作爲例子來演示。
 
首先,Weblogic Server提供了一系列的參數來控制它的HttpSession的實現,包括使用cookie的開關選項,使用URL重寫的開關選項,session持久化的設置,session失效時間的設置,以及針對cookie的各種設置,比如設置cookie的名字、路徑、域,cookie的生存時間等。
 
一般情況下,session都是存儲在內存裏,當服務器進程被停止或者重啓的時候,內存裏的session也會被清空,如果設置了session的持久化特性,服務器就會把session保存到硬盤上,當服務器進程重新啓動或這些信息將能夠被再次使用,Weblogic Server支持的持久性方式包括文件、數據庫、客戶端cookie保存和複製。
 
複製嚴格說來不算持久化保存,因爲session實際上還是保存在內存裏,不過同樣的信息被複制到各個cluster內的服務器進程中,這樣即使某個服務器進程停止工作也仍然可以從其他進程中取得session。
 
cookie生存時間的設置則會影響瀏覽器生成的cookie是否是一個會話cookie。默認是使用會話cookie。有興趣的可以用它來試驗我們在第四節裏提到的那個誤解。
 
cookie的路徑對於web應用程序來說是一個非常重要的選項,Weblogic Server對這個選項的默認處理方式使得它與其他服務器有明顯的區別。後面我們會專題討論。
 
關於session的設置參考[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#
 
 
 
六、HttpSession常見問題
(在本小節中session的含義爲⑤和⑥的混合)
 
1、session在何時被創建
一個常見的誤解是以爲session在有客戶端訪問時就被創建,然而事實是直到某server端程序調用HttpServletRequest.getSession(true)這樣的語句時才被創建,注意如果JSP沒有顯示的使用 <%@page session="false"%> 關閉session,則JSP文件在編譯成Servlet時將會自動加上這樣一條語句HttpSession session = HttpServletRequest.getSession(true);這也是JSP中隱含的session對象的來歷。
 
由於session會消耗內存資源,因此,如果不打算使用session,應該在所有的JSP中關閉它。
 
 
2、session何時被刪除
綜合前面的討論,session在下列情況下被刪除a.程序調用HttpSession.invalidate();或b.距離上一次收到客戶端發送的session id時間間隔超過了session的超時設置;或c.服務器進程被停止(非持久session)
 
 
3、如何做到在瀏覽器關閉時刪除session
嚴格的講,做不到這一點。可以做一點努力的辦法是在所有的客戶端頁面裏使用javascrīpt代碼window.oncolose來監視瀏覽器的關閉動作,然後向服務器發送一個請求來刪除session。但是對於瀏覽器崩潰或者強行殺死進程這些非常規手段仍然無能爲力。
 
 
4、有個HttpSessionListener是怎麼回事
你可以創建這樣的listener去監控session的創建和銷燬事件,使得在發生這樣的事件時你可以做一些相應的工作。注意是session的創建和銷燬動作觸發listener,而不是相反。類似的與HttpSession有關的listener還有HttpSessionBindingListener,HttpSessionActivationListener和HttpSessionAttributeListener。
 
 
5、存放在session中的對象必須是可序列化的嗎
不是必需的。要求對象可序列化只是爲了session能夠在集羣中被複制或者能夠持久保存或者在必要時server能夠暫時把session交換出內存。在Weblogic Server的session中放置一個不可序列化的對象在控制檯上會收到一個警告。我所用過的某個iPlanet版本如果session中有不可序列化的對象,在session銷燬時會有一個Exception,很奇怪。
 
 
6、如何才能正確的應付客戶端禁止cookie的可能性
對所有的URL使用URL重寫,包括超鏈接,form的action,和重定向的URL,具體做法參見[6]http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770
 
 
7、開兩個瀏覽器窗口訪問應用程序會使用同一個session還是不同的session
參見第三小節對cookie的討論,對session來說是隻認id不認人,因此不同的瀏覽器,不同的窗口打開方式以及不同的cookie存儲方式都會對這個問題的答案有影響。
 
 
8、如何防止用戶打開兩個瀏覽器窗口操作導致的session混亂
這個問題與防止表單多次提交是類似的,可以通過設置客戶端的令牌來解決。就是在服務器每次生成一個不同的id返回給客戶端,同時保存在session裏,客戶端提交表單時必須把這個id也返回服務器,程序首先比較返回的id與保存在session裏的值是否一致,如果不一致則說明本次操作已經被提交過了。可以參看《J2EE核心模式》關於表示層模式的部分。需要注意的是對於使用javascrīpt window.open打開的窗口,一般不設置這個id,或者使用單獨的id,以防主窗口無法操作,建議不要再window.open打開的窗口裏做修改操作,這樣就可以不用設置。
 
 
9、爲什麼在Weblogic Server中改變session的值後要重新調用一次session.setValue
做這個動作主要是爲了在集羣環境中提示Weblogic Server session中的值發生了改變,需要向其他服務器進程複製新的session值。
 
 
10、爲什麼session不見了
排除session正常失效的因素之外,服務器本身的可能性應該是微乎其微的,雖然筆者在iPlanet6SP1加若干補丁的Solaris版本上倒也遇到過;瀏覽器插件的可能性次之,筆者也遇到過3721插件造成的問題;理論上防火牆或者代理服務器在cookie處理上也有可能會出現問題。
出現這一問題的大部分原因都是程序的錯誤,最常見的就是在一個應用程序中去訪問另外一個應用程序。我們在下一節討論這個問題。
 
 
 
七、跨應用程序的session共享
 
常常有這樣的情況,一個大項目被分割成若干小項目開發,爲了能夠互不干擾,要求每個小項目作爲一個單獨的web應用程序開發,可是到了最後突然發現某幾個小項目之間需要共享一些信息,或者想使用session來實現SSO(single sign on),在session中保存login的用戶信息,最自然的要求是應用程序間能夠訪問彼此的session。
 
然而按照Servlet規範,session的作用範圍應該僅僅限於當前應用程序下,不同的應用程序之間是不能夠互相訪問對方的session的。各個應用服務器從實際效果上都遵守了這一規範,但是實現的細節卻可能各有不同,因此解決跨應用程序session共享的方法也各不相同。
 
首先來看一下Tomcat是如何實現web應用程序之間session的隔離的,從Tomcat設置的cookie路徑來看,它對不同的應用程序設置的cookie路徑是不同的,這樣不同的應用程序所用的session id是不同的,因此即使在同一個瀏覽器窗口裏訪問不同的應用程序,發送給服務器的session id也可以是不同的。
 
 
 
 
根據這個特性,我們可以推測Tomcat中session的內存結構大致如下。
 
 
 
 
筆者以前用過的iPlanet也採用的是同樣的方式,估計SunONE與iPlanet之間不會有太大的差別。對於這種方式的服務器,解決的思路很簡單,實際實行起來也不難。要麼讓所有的應用程序共享一個session id,要麼讓應用程序能夠獲得其他應用程序的session id。
 
iPlanet中有一種很簡單的方法來實現共享一個session id,那就是把各個應用程序的cookie路徑都設爲/(實際上應該是/NASApp,對於應用程序來講它的作用相當於根)。
<session-info>
<path>/NASApp</path>
</session-info>
 
需要注意的是,操作共享的session應該遵循一些編程約定,比如在session attribute名字的前面加上應用程序的前綴,使得setAttribute("name", "neo")變成setAttribute("app1.name", "neo"),以防止命名空間衝突,導致互相覆蓋。
 
 
 
Tomcat中則沒有這麼方便的選擇。在Tomcat版本3上,我們還可以有一些手段來共享session。對於版本4以上的Tomcat,目前筆者尚未發現簡單的辦法。只能藉助於第三方的力量,比如使用文件、數據庫、JMS或者客戶端cookie,URL參數或者隱藏字段等手段。
 
我們再看一下Weblogic Server是如何處理session的。
 
 
 
 
 
從截屏畫面上可以看到Weblogic Server對所有的應用程序設置的cookie的路徑都是/,這是不是意味着在Weblogic Server中默認的就可以共享session了呢?然而一個小實驗即可證明即使不同的應用程序使用的是同一個session,各個應用程序仍然只能訪問自己所設置的那些屬性。這說明Weblogic Server中的session的內存結構可能如下
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章