1. 程式人生 > >正確理解session:使用HttpSession進行會話管理

正確理解session:使用HttpSession進行會話管理

1. Session模型:

    1) HTTP協議是無狀態的,無法記錄多次請求/響應之間的聯絡,而Session模型就好比一箇中間人,可以幫助使用HTTP協議通訊的雙方記錄每次通訊的內容(即會話的內容),因此Session模型就是一種中間人模型,可以儲存通訊記錄;

    2) HttpSession對Session模型的實現:

         i. 當客戶端第一次請求伺服器時伺服器可以主動建立一個HttpSession物件專門用於記錄該客戶端和自己這一次,包括今後將要發生的多次,通訊記錄,建立HttpSession就是建立會話,這種會話(會話物件)可以長期儲存;

         ii. Web容器會為每個會話分配一個唯一的ID號,容器會將相關通訊記錄都儲存在相應ID的會話物件中,並可以將這些會話物件長期儲存在Web容器中(伺服器端);

         iii. 而Servlet響應客戶端時只需要將相應會話的ID儲存在Cookie中返回即可,而瀏覽器下次再請求時只需要憑Cookie中的會話物件的ID讓Web容器調出儲存在其中的會話物件即可;

    3) 大致模型就是:

客戶端(Cookie:Session ID) <====>   伺服器端(很多Session物件)

!伺服器根據客戶端請求Cookie中的Session ID調出儲存在Web容器中相應的Session物件,然後取出物件中儲存的前幾次通訊的記錄並利用!

2. 使用HttpSession的基本流程:

   1) 建立或獲取Session物件要使用HttpServletRequest的getSession函式:

        i. HttpSession HttpServletRequest.getSession(); // 如果通訊雙方建立過會話則返回之前儲存在Web容器中的會話,否則就建立一個新的會話

        ii. HttpSession HttpServletRequest.getSession(boolean create); // true就和getSession等價,而false在沒有建立過會話的條件下返回null,否則返回相應的會話

        !!通常使用前者較多;

    2) 插入和提取會話記錄:

         i. 插入會話記錄使用HttpSession的setAttribute,提取會話記錄使用getAttribute,用法和HttpServletRequest的setAttribute和getAttribute一模一樣,會話記錄也是以“鍵值對”的形式儲存;

         ii. Object HttpSession.getAttribute(String name);  // 提取相應引數名的物件

         iii. void HttpSession.setAttribute(String name, Object value);  // 設定鍵值對

!!會話記錄都是以類物件的形式儲存的,提取出來需要型別轉換一下才能放心使用;

2. 會話模型的具體實現:

    1) 在建立Session的時候Web容器會為每個Session分配一個唯一的ID號,因此一個HttpSession物件中儲存有ID號和各個鍵值對(會話記錄);

    2) Session物件都儲存在Web容器中;

    3) 在響應客戶端時Web容器會自動把本次通訊的Session的ID加入到Cookie中返回給客戶端,其在set-cookie標頭中的引數名為JSESSIONID(在Tomcat中是這樣),例如:set-cookie: k1=v1; k2=v2…JSESSIONID=C8D2S02LA23…kn=vn….

    4) 客戶端和伺服器端通訊只傳送Session的ID而不傳送Session中的通訊記錄,當伺服器端收到客戶端請求並呼叫getSession時,就會根據請求Cookie中的Session ID從Web容器快取中調出相應的Session物件,這樣通訊時就能節省很多容量資源,加大網路流量的利用率同時提高效率,只不過通訊記錄都是儲存在伺服器端的,因此伺服器端的儲存壓力較大;

3. HttpSession的常用方法以及配置:

    1) 獲取Session的ID:String getId();

    2) 設定Session的存活期限:void setMaxInactiveInterval(int interval);  // 設定請求間隔時間(單位是秒),當瀏覽器超出interval秒還沒有請求該應用的話就清除該Session(釋放記憶體)

!!如果interval為0或負則表示Session可以無限存活(除非關閉Web容器);

!!由於用伺服器來儲存通訊記錄是非常消耗記憶體資源的,因此建議不要將大型物件儲存在Session中,如果Session中的物件較大那麼設定存活期限就相當必要,否則會導致記憶體不足降低服務效率;

    3) 在web.xml中配置Session的預設存活時間:如果沒有呼叫setMaxInactiveInterval則使用web.xml中的預設值,否則就使用程式中設定的值

         i. 所有關於Session的配置都放在<web-app>的<session-config>中;

         ii. 存活時間的配置標籤是<session-timeout>,但是單位是分鐘!!!和set函式單位是秒不一樣,千萬別搞錯了!!

         iii. 示例:

  1. ...
  2. <web-app>
  3. ...
  4. <session-config>
  5. <session-timeout>30</session-timeout>
  6. </session-config>
  7. ...
  8. </web-app>
  9. ...
!!!這裡設定的是30分鐘而不是30秒;

    3) Session ID的Cookie配置:

         i. 預設情況下,Web容器自動為Session建立的傳送ID的Cookie的max-age(Cookie存活時長)為“退出時長”,“退出時常”是指Cookie的存活時間為從建立到瀏覽器關閉那麼久,一旦瀏覽器退出那麼該Cookie就會被清除,不會儲存到下次瀏覽器開啟;

         ii. 因此在預設情況下,瀏覽器退出再開啟後再次請求該網站,那麼請求Cookie中就沒有Session ID的資訊了,那麼伺服器端使用getSession時就沒有ID可以查詢,那麼此時就會建立一個新的Session,因此之前的通訊記錄就無法再獲取了,即使記錄前幾次通訊記錄的Session物件還可能存活在Web容器的快取中,但是由於調出該物件的請求不復存在了,因此該Session也只能深埋在快取中直到達到存活期限被銷燬;

         iii. 所以我們希望修改Session ID的Cookie的存活時間,關於Session ID的Cookie的配置可以在web.xml中進行:

              a. 在<session-config>標籤下的<cookie-config>中配置即可;

              b. <name>標籤可以設定Cookie的名稱,可以將預設的JSESSIONID的名稱改成其它你想要的;

              c. <max-age>標籤可以修改Cookie的存活時間,單位為秒;

              d. 示例:

  1. <session-config>
  2. <session-timeout>30</session-timeout>
  3. <cookie-config>
  4. <name>SID</name>
  5. <max-age>5000</max-age>
  6. </cookie-config>
  7. </session-config>
    4) 使Session物件立即無效(Web容器會立即銷燬該物件並回收其記憶體空間):void invalidate();

!!呼叫後不得在使用其它函式獲取、修改Session中的資訊,因為其空間已經被回收了,更不能再次invalidate,因為此時引用已經和物件脫鉤,如果發生以上任何一種行為都會引發指標異常並丟擲IllegalStateException異常;

!!這就相當於C++中手動呼叫解構函式;