日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

tomcat架构分析 (Session管理)【转】

發布時間:2025/4/5 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 tomcat架构分析 (Session管理)【转】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文地址:https://www.iteye.com/blog/gearever-1546423

Session管理是JavaEE容器比較重要的一部分,在app中也經常會用到。在開發app時,我們只是獲取一個session,然后向 session中存取數據,然后再銷毀session。那么如何產生session,以及session池如何維護及管理,這些并沒有在app涉及到。這 些工作都是由容器來完成的。?
Tomcat中主要由每個context容器內的一個Manager對象來管理session。對于這個manager對象的實現,可以根據tomcat提供的接口或基類來自己定制,同時,tomcat也提供了標準實現。?
在tomcat架構分析(容器類)中已經介紹過,在每個context對象,即web app都具有一個獨立的manager對象。通過server.xml可以配置定制化的manager,也可以不配置。不管怎樣,在生成context對 象時,都會生成一個manager對象。缺省的是StandardManager類,其類路徑為:

引用 org.apache.catalina.session.StandardManager


Session對象也可以定制化實現,其主要實現標準servlet的session接口:

引用 javax.servlet.http.HttpSession


Tomcat也提供了標準的session實現:

引用 org.apache.catalina.session.StandardSession


本文主要就是結合消息流程介紹這兩個類的實現,及session機制。?
Session方面牽涉的東西還是蠻多的,例如HA,session復制是其中重要部分等,不過本篇主要從功能方面介紹session管理,有時間再說說擴展。?
Session管理主要涉及到這幾個方面:

  • 創建session
  • 注銷session
  • 持久化及啟動加載session



創建session?
在具體說明session的創建過程之前,先看一下BS訪問模型吧,這樣理解直觀一點。?

  • browser發送Http request;
  • tomcat內核Http11Processor會從HTTP request中解析出“jsessionid”(具體的解析過程為先從request的URL中解析,這是為了有的瀏覽器把cookie功能禁止后,將 URL重寫考慮的,如果解析不出來,再從cookie中解析相應的jsessionid),解析完后封裝成一個request對象(當然還有其他的 http header);
  • servlet中獲取session,其過程是根據剛才解析得到的jsessionid(如果有的話),從session池 (session maps)中獲取相應的session對象;這個地方有個邏輯,就是如果jsessionid為空的話(或者沒有其對應的session對象,或者有 session對象,但此對象已經過期超時),可以選擇創建一個session,或者不創建;
  • 如果創建新session,則將session放入session池中,同時將與其相對應的jsessionid寫入cookie通過Http response header的方式發送給browser,然后重復第一步。

  • 以上是session的獲取及創建過程。在servlet中獲取session,通常是調用request的getSession方法。這個方法 需要傳入一個boolean參數,這個參數就是實現剛才說的,當jsessionid為空或從session池中獲取不到相應的session對象時,選 擇創建一個新的session還是不創建。?
    看一下核心代碼邏輯;

    Java代碼 ??
  • protected?Session?doGetSession(boolean?create)?{??
  • ??
  • ????????……??
  • ????????//?先獲取所在context的manager對象??
  • ????????Manager?manager?=?null;??
  • ????????if?(context?!=?null)??
  • ????????????manager?=?context.getManager();??
  • ????????if?(manager?==?null)??
  • ????????????return?(null);??????//?Sessions?are?not?supported??
  • ??????????
  • ????????//這個requestedSessionId就是從Http?request中解析出來的??
  • ????????if?(requestedSessionId?!=?null)?{??
  • ????????????try?{??
  • ????????????????//manager管理的session池中找相應的session對象??
  • ????????????????session?=?manager.findSession(requestedSessionId);??
  • ????????????}?catch?(IOException?e)?{??
  • ????????????????session?=?null;??
  • ????????????}??
  • ????????????//判斷session是否為空及是否過期超時??
  • ????????????if?((session?!=?null)?&&?!session.isValid())??
  • ????????????????session?=?null;??
  • ????????????if?(session?!=?null)?{??
  • ????????????????//session對象有效,記錄此次訪問時間??
  • ????????????????session.access();??
  • ????????????????return?(session);??
  • ????????????}??
  • ????????}??
  • ??
  • ????????//?如果參數是false,則不創建新session對象了,直接退出了??
  • ????????if?(!create)??
  • ????????????return?(null);??
  • ????????if?((context?!=?null)?&&?(response?!=?null)?&&??
  • ????????????context.getCookies()?&&??
  • ????????????response.getResponse().isCommitted())?{??
  • ????????????throw?new?IllegalStateException??
  • ??????????????(sm.getString("coyoteRequest.sessionCreateCommitted"));??
  • ????????}??
  • ??
  • ????????//?開始創建新session對象??
  • ????????if?(connector.getEmptySessionPath()???
  • ????????????????&&?isRequestedSessionIdFromCookie())?{??
  • ????????????session?=?manager.createSession(getRequestedSessionId());??
  • ????????}?else?{??
  • ????????????session?=?manager.createSession(null);??
  • ????????}??
  • ??
  • ????????//?將新session的jsessionid寫入cookie,傳給browser??
  • ????????if?((session?!=?null)?&&?(getContext()?!=?null)??
  • ???????????????&&?getContext().getCookies())?{??
  • ????????????Cookie?cookie?=?new?Cookie(Globals.SESSION_COOKIE_NAME,??
  • ???????????????????????????????????????session.getIdInternal());??
  • ????????????configureSessionCookie(cookie);??
  • ????????????response.addCookieInternal(cookie);??
  • ????????}??
  • ????????//記錄session最新訪問時間??
  • ????????if?(session?!=?null)?{??
  • ????????????session.access();??
  • ????????????return?(session);??
  • ????????}?else?{??
  • ????????????return?(null);??
  • ????????}??
  • ????}??

  • 盡管不能貼出所有代碼,但是上述的核心邏輯還是很清晰的。從中也可以看出,我們經常在servlet中這兩種調用方式的不同;?
    新創建session

    引用 request.getSession(); 或者request.getSession(true);


    不創建session

    引用 request.getSession(false);


    接下來,看一下StandardManager的createSession方法,了解一下session的創建過程;

    Java代碼 ??
  • public?Session?createSession(String?sessionId)?{??
  • 是個session數量控制邏輯,超過上限則拋異常退出??
  • ????if?((maxActiveSessions?>=?0)?&&??
  • ????????(sessions.size()?>=?maxActiveSessions))?{??
  • ????????rejectedSessions++;??
  • ????????throw?new?IllegalStateException??
  • ????????????(sm.getString("standardManager.createSession.ise"));??
  • ????}??
  • ????return?(super.createSession(sessionId));??
  • }??

  • 這個最大支持session數量maxActiveSessions是可以配置的,先不管這個安全控制邏輯,看其主邏輯,即調用其基類的createSession方法;

    Java代碼 ??
  • public?Session?createSession(String?sessionId)?{??
  • ??????????
  • ????????//?創建一個新的StandardSession對象??
  • ????????Session?session?=?createEmptySession();??
  • ??
  • ????????//?Initialize?the?properties?of?the?new?session?and?return?it??
  • ????????session.setNew(true);??
  • ????????session.setValid(true);??
  • ????????session.setCreationTime(System.currentTimeMillis());??
  • ????????session.setMaxInactiveInterval(this.maxInactiveInterval);??
  • ????????if?(sessionId?==?null)?{??
  • ????????????//設置jsessionid??
  • ????????????sessionId?=?generateSessionId();??
  • ????????}??
  • ????????session.setId(sessionId);??
  • ????????sessionCounter++;??
  • ????????return?(session);??
  • ????}??

  • 關鍵是jsessionid的產生過程,接著看generateSessionId方法;

    Java代碼 ??
  • protected?synchronized?String?generateSessionId()?{??
  • ??
  • ????????byte?random[]?=?new?byte[16];??
  • ????????String?jvmRoute?=?getJvmRoute();??
  • ????????String?result?=?null;??
  • ??
  • ????????//?Render?the?result?as?a?String?of?hexadecimal?digits??
  • ????????StringBuffer?buffer?=?new?StringBuffer();??
  • ????????do?{??
  • ????????????int?resultLenBytes?=?0;??
  • ????????????if?(result?!=?null)?{??
  • ????????????????buffer?=?new?StringBuffer();??
  • ????????????????duplicates++;??
  • ????????????}??
  • ??
  • ????????????while?(resultLenBytes?<?this.sessionIdLength)?{??
  • ????????????????getRandomBytes(random);??
  • ????????????????random?=?getDigest().digest(random);??
  • ????????????????for?(int?j?=?0;??
  • ????????????????j?<?random.length?&&?resultLenBytes?<?this.sessionIdLength;??
  • ????????????????j++)?{??
  • ????????????????????byte?b1?=?(byte)?((random[j]?&?0xf0)?>>?4);??
  • ????????????????????byte?b2?=?(byte)?(random[j]?&?0x0f);??
  • ????????????????????if?(b1?<?10)??
  • ????????????????????????buffer.append((char)?('0'?+?b1));??
  • ????????????????????else??
  • ????????????????????????buffer.append((char)?('A'?+?(b1?-?10)));??
  • ????????????????????if?(b2?<?10)??
  • ????????????????????????buffer.append((char)?('0'?+?b2));??
  • ????????????????????else??
  • ????????????????????????buffer.append((char)?('A'?+?(b2?-?10)));??
  • ????????????????????resultLenBytes++;??
  • ????????????????}??
  • ????????????}??
  • ????????????if?(jvmRoute?!=?null)?{??
  • ????????????????buffer.append('.').append(jvmRoute);??
  • ????????????}??
  • ????????????result?=?buffer.toString();??
  • ????????//注意這個do…while結構??
  • ????????}?while?(sessions.containsKey(result));??
  • ????????return?(result);??
  • ????}??

  • 這里主要說明的不是生成jsessionid的算法了,而是這個do…while結構。把這個邏輯抽象出來,可以看出;?

    如圖所示,創建jsessionid的方式是由tomcat內置的加密算法算出一個隨機的jsessionid,如果此jsessionid已經存在,則重新計算一個新的,直到確保現在計算的jsessionid唯一。?
    好了,至此一個session就這么創建了,像上面所說的,返回時是將jsessionid以HTTP response的header:“Set-cookie”發給客戶端。?
    注銷session

    • 主動注銷
    • 超時注銷


    Session創建完之后,不會一直存在,或是主動注銷,或是超時清除。即是出于安全考慮也是為了節省內存空間等。例如,常見場景:用戶登出系統時,會主動觸發注銷操作。?
    主動注銷?
    主動注銷時,是調用標準的servlet接口:

    引用 session.invalidate();


    看一下tomcat提供的標準session實現(StandardSession)

    Java代碼 ??
  • public?void?invalidate()?{??
  • ????????if?(!isValidInternal())??
  • ????????????throw?new?IllegalStateException??
  • ????????????????(sm.getString("standardSession.invalidate.ise"));??
  • ????????//?明顯的注銷方法??
  • ????????expire();??
  • ????}??

  • Expire方法的邏輯稍后再說,先看看超時注銷,因為它們調用的是同一個expire方法。?
    超時注銷?
    Tomcat定義了一個最大空閑超時時間,也就是說當session沒有被操作超過這個最大空閑時間時間時,再次操作這個session,這個session就會觸發expire。?
    這個方法封裝在StandardSession中的isValid()方法內,這個方法在獲取這個request請求對應的session對象時 調用,可以參看上面說的創建session環節。也就是說,獲取session的邏輯是,先從manager控制的session池中獲取對應 jsessionid的session對象,如果獲取到,就再判斷是否超時,如果超時,就expire這個session了。?
    看一下tomcat提供的標準session實現(StandardSession)

    Java代碼 ??
  • public?boolean?isValid()?{??
  • ????????……??
  • ????????//這就是判斷距離上次訪問是否超時的過程??
  • ????????if?(maxInactiveInterval?>=?0)?{???
  • ????????????long?timeNow?=?System.currentTimeMillis();??
  • ????????????int?timeIdle?=?(int)?((timeNow?-?thisAccessedTime)?/?1000L);??
  • ????????????if?(timeIdle?>=?maxInactiveInterval)?{??
  • ????????????????expire(true);??
  • ????????????}??
  • ????????}??
  • ????????return?(this.isValid);??
  • ????}??

  • Expire方法?
    是時候來看看expire方法了。

    Java代碼 ??
  • public?void?expire(boolean?notify)?{???
  • ??
  • ????????synchronized?(this)?{??
  • ????????????......??
  • ????????????//設立標志位??
  • ????????????setValid(false);??
  • ??
  • ????????????//計算一些統計值,例如此manager下所有session平均存活時間等??
  • ????????????long?timeNow?=?System.currentTimeMillis();??
  • ????????????int?timeAlive?=?(int)?((timeNow?-?creationTime)/1000);??
  • ????????????synchronized?(manager)?{??
  • ????????????????if?(timeAlive?>?manager.getSessionMaxAliveTime())?{??
  • ????????????????????manager.setSessionMaxAliveTime(timeAlive);??
  • ????????????????}??
  • ????????????????int?numExpired?=?manager.getExpiredSessions();??
  • ????????????????numExpired++;??
  • ????????????????manager.setExpiredSessions(numExpired);??
  • ????????????????int?average?=?manager.getSessionAverageAliveTime();??
  • ????????????????average?=?((average?*?(numExpired-1))?+?timeAlive)/numExpired;??
  • ????????????????manager.setSessionAverageAliveTime(average);??
  • ????????????}??
  • ??
  • ????????????//?將此session從manager對象的session池中刪除??
  • ????????????manager.remove(this);??
  • ????????????......??
  • ????????}??
  • ????}??

  • 不需要解釋,已經很清晰了。?
    這個超時時間是可以配置的,缺省在tomcat的全局web.xml下配置,也可在各個app下的web.xml自行定義;

    Xml代碼 ??
  • <session-config>??
  • ????<session-timeout>30</session-timeout>??
  • </session-config>??

  • 單位是分鐘。?
    Session持久化及啟動初始化?
    這個功能主要是,當tomcat執行安全退出時(通過執行shutdown腳本),會將session持久化到本地文件,通常在tomcat的部 署目錄下有個session.ser文件。當啟動tomcat時,會從這個文件讀入session,并添加到manager的session池中去。?
    這樣,當tomcat正常重啟時, session沒有丟失,對于用戶而言,體會不到重啟,不影響用戶體驗。?
    看一下概念圖吧,覺得不是重要實現邏輯,代碼就不說了。?

    Session持久化可以實現當tomcat重新啟動后,當前IE使用的session仍然有效而不用重新登錄,有兩步需要做,session持久 化很有用,尤其在eclipse中重新增加類后,tomcat重新加載后,IE頁面不用再登錄,之前的session依舊保持,調試的時候很有用
    1.配置conf/server.xml
    在server.xml的根路徑或虛擬目錄中增加一段,如虛擬目錄調度所中:
    <Context path="/dds" docBase="D:/01_XZY/98_供電局調度所/02_JSP/HRDGDZC/ROOT" debug="0" reloadable="true" >
    <Manager className="org.apache.catalina.session.PersistentManager" debug="0" saveOnRestart="true" maxActiveSessions="-1" minIdleSwap="-1" maxIdleSwap="-1" maxIdleBackup="-1" >
    <Store className="org.apache.catalina.session.FileStore" directory="seskep"/>
    </Manager>
    </Context>
    這樣之后,普通的session對象(像字符串類的)就能實現持久化了,但如果session使用了對象,則必須實現對象類的可序列化
    參數說明:saveOnRestart-服務器關閉時,是否將所有的session保存到文件中;
    maxActiveSessions-可處于活動狀態的session數;
    minIdleSwap/maxIdleSwap-session處于不活動狀態最短/長時間(s),sesson對象轉移到File Store中;
    maxIdleBackup-超過這一時間,將session備份。(-1表示沒有限制)
    directory="seskep"? 會在tomcat的work目錄下建立一個目錄,用來存儲session,這里建立的目錄是
    D:/JAVA/TOMCAT4/work/Standalone/localhost/dds/seskep

    2.類的序列化
    如果session中存儲了類xzy登錄屬性的實例,則類xzy登錄屬性必須能夠序列化,才能實現session持久化
    實現implements java.io.Serializable接口就可以了

    public class xzy登錄屬性 implements java.io.Serializable?
    {
    ? public String UserName=null;
    ? public String 姓名=null;
    ? public String 單位=null;
    ? public String 部門=null;
    ? public String 職務=null;
    ? public String 權限設置=null;
    ? static final public long serialVersionUID=372938;
    }
    serialVersionUID這個東西估計每個類中寫個不同的數值就可以了,好像是版本保持的.
    經過測試IE登錄后頁面后,Session再重新啟動,刷新IE頁面的時候session對象中的值能夠像重啟前一樣的讀出來.


    總結?
    由此可以看出,session的管理是容器層做的事情,應用層一般不會參與session的管理,也就是說,如果在應用層獲取到相應的 session,已經是由tomcat提供的,因此如果過多的依賴session機制來進行一些操作,例如訪問控制,安全登錄等就不是十分的安全,因為如 果有人能得到正在使用的jsessionid,則就可以侵入系統。

    轉載于:https://www.cnblogs.com/davidwang456/articles/11452811.html

    總結

    以上是生活随笔為你收集整理的tomcat架构分析 (Session管理)【转】的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。