<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      tomcat之Session的管理

      Session是由服務(wù)器端的應(yīng)用服務(wù)器容器(如Tomcat、Jetty)存儲的。下面分析一下Tomcat是如何管理Session的。

      轉(zhuǎn)自:tomcat架構(gòu)分析 (Session管理)

      Tomcat中主要由每個context容器內(nèi)的一個Manager對象來管理session。對于這個manager對象的實現(xiàn),可以根據(jù)tomcat提供的接口或基類來自己定制,同時,tomcat也提供了標準實現(xiàn)。 
      在每個context對象,即web app都具有一個獨立的manager對象。通過server.xml可以配置定制化的manager,也可以不配置。不管怎樣,在生成context對象時,都會生成一個manager對象。缺省的是StandardManager類,其類路徑為: 

      引用
      org.apache.catalina.session.StandardManager


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

      引用
      javax.servlet.http.HttpSession


      Tomcat也提供了標準的session實現(xiàn): 

      引用
      org.apache.catalina.session.StandardSession


      Session管理主要涉及到這幾個方面: 

      • 創(chuàng)建session
      • 注銷session
      • 持久化及啟動加載session



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

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


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

      Java代碼  收藏代碼
      1. protected Session doGetSession(boolean create) {  
      2.   
      3.         ……  
      4.         // 先獲取所在context的manager對象  
      5.         Manager manager = null;  
      6.         if (context != null)  
      7.             manager = context.getManager();  
      8.         if (manager == null)  
      9.             return (null);      // Sessions are not supported  
      10.           
      11.         //這個requestedSessionId就是從Http request中解析出來的  
      12.         if (requestedSessionId != null) {  
      13.             try {  
      14.                 //manager管理的session池中找相應(yīng)的session對象  
      15.                 session = manager.findSession(requestedSessionId);  
      16.             } catch (IOException e) {  
      17.                 session = null;  
      18.             }  
      19.             //判斷session是否為空及是否過期超時  
      20.             if ((session != null) && !session.isValid())  
      21.                 session = null;  
      22.             if (session != null) {  
      23.                 //session對象有效,記錄此次訪問時間  
      24.                 session.access();  
      25.                 return (session);  
      26.             }  
      27.         }  
      28.   
      29.         // 如果參數(shù)是false,則不創(chuàng)建新session對象了,直接退出了  
      30.         if (!create)  
      31.             return (null);  
      32.         if ((context != null) && (response != null) &&  
      33.             context.getCookies() &&  
      34.             response.getResponse().isCommitted()) {  
      35.             throw new IllegalStateException  
      36.               (sm.getString("coyoteRequest.sessionCreateCommitted"));  
      37.         }  
      38.   
      39.         // 開始創(chuàng)建新session對象  
      40.         if (connector.getEmptySessionPath()   
      41.                 && isRequestedSessionIdFromCookie()) {  
      42.             session = manager.createSession(getRequestedSessionId());  
      43.         } else {  
      44.             session = manager.createSession(null);  
      45.         }  
      46.   
      47.         // 將新session的jsessionid寫入cookie,傳給browser  
      48.         if ((session != null) && (getContext() != null)  
      49.                && getContext().getCookies()) {  
      50.             Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,  
      51.                                        session.getIdInternal());  
      52.             configureSessionCookie(cookie);  
      53.             response.addCookieInternal(cookie);  
      54.         }  
      55.         //記錄session最新訪問時間  
      56.         if (session != null) {  
      57.             session.access();  
      58.             return (session);  
      59.         } else {  
      60.             return (null);  
      61.         }  
      62.     }  


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

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


      不創(chuàng)建session 

      引用
      request.getSession(false);


      接下來,看一下StandardManager的createSession方法,了解一下session的創(chuàng)建過程; 

      Java代碼  收藏代碼
      1. public Session createSession(String sessionId) {  
      2. 是個session數(shù)量控制邏輯,超過上限則拋異常退出  
      3.     if ((maxActiveSessions >= 0) &&  
      4.         (sessions.size() >= maxActiveSessions)) {  
      5.         rejectedSessions++;  
      6.         throw new IllegalStateException  
      7.             (sm.getString("standardManager.createSession.ise"));  
      8.     }  
      9.     return (super.createSession(sessionId));  
      10. }  


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

      Java代碼  收藏代碼
      1. public Session createSession(String sessionId) {  
      2.           
      3.         // 創(chuàng)建一個新的StandardSession對象  
      4.         Session session = createEmptySession();  
      5.   
      6.         // Initialize the properties of the new session and return it  
      7.         session.setNew(true);  
      8.         session.setValid(true);  
      9.         session.setCreationTime(System.currentTimeMillis());  
      10.         session.setMaxInactiveInterval(this.maxInactiveInterval);  
      11.         if (sessionId == null) {  
      12.             //設(shè)置jsessionid  
      13.             sessionId = generateSessionId();  
      14.         }  
      15.         session.setId(sessionId);  
      16.         sessionCounter++;  
      17.         return (session);  
      18.     }  


      關(guān)鍵是jsessionid的產(chǎn)生過程,接著看generateSessionId方法; 

      Java代碼  收藏代碼
      1. protected synchronized String generateSessionId() {  
      2.   
      3.         byte random[] = new byte[16];  
      4.         String jvmRoute = getJvmRoute();  
      5.         String result = null;  
      6.   
      7.         // Render the result as a String of hexadecimal digits  
      8.         StringBuffer buffer = new StringBuffer();  
      9.         do {  
      10.             int resultLenBytes = 0;  
      11.             if (result != null) {  
      12.                 buffer = new StringBuffer();  
      13.                 duplicates++;  
      14.             }  
      15.   
      16.             while (resultLenBytes < this.sessionIdLength) {  
      17.                 getRandomBytes(random);  
      18.                 random = getDigest().digest(random);  
      19.                 for (int j = 0;  
      20.                 j < random.length && resultLenBytes < this.sessionIdLength;  
      21.                 j++) {  
      22.                     byte b1 = (byte) ((random[j] & 0xf0) >> 4);  
      23.                     byte b2 = (byte) (random[j] & 0x0f);  
      24.                     if (b1 < 10)  
      25.                         buffer.append((char) ('0' + b1));  
      26.                     else  
      27.                         buffer.append((char) ('A' + (b1 - 10)));  
      28.                     if (b2 < 10)  
      29.                         buffer.append((char) ('0' + b2));  
      30.                     else  
      31.                         buffer.append((char) ('A' + (b2 - 10)));  
      32.                     resultLenBytes++;  
      33.                 }  
      34.             }  
      35.             if (jvmRoute != null) {  
      36.                 buffer.append('.').append(jvmRoute);  
      37.             }  
      38.             result = buffer.toString();  
      39.         //注意這個do…while結(jié)構(gòu)  
      40.         } while (sessions.containsKey(result));  
      41.         return (result);  
      42.     }  


      這里主要說明的不是生成jsessionid的算法了,而是這個do…while結(jié)構(gòu)。把這個邏輯抽象出來,可以看出; 
       
      如圖所示,創(chuàng)建jsessionid的方式是由tomcat內(nèi)置的加密算法算出一個隨機的jsessionid,如果此jsessionid已經(jīng)存在,則重新計算一個新的,直到確?,F(xiàn)在計算的jsessionid唯一。 
      好了,至此一個session就這么創(chuàng)建了,像上面所說的,返回時是將jsessionid以HTTP response的header:“Set-cookie”發(fā)給客戶端。 
      注銷session 

      • 主動注銷
      • 超時注銷


      Session創(chuàng)建完之后,不會一直存在,或是主動注銷,或是超時清除。即是出于安全考慮也是為了節(jié)省內(nèi)存空間等。例如,常見場景:用戶登出系統(tǒng)時,會主動觸發(fā)注銷操作。 
      主動注銷 
      主動注銷時,是調(diào)用標準的servlet接口: 

      引用
      session.invalidate();


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

      Java代碼  收藏代碼
      1. public void invalidate() {  
      2.         if (!isValidInternal())  
      3.             throw new IllegalStateException  
      4.                 (sm.getString("standardSession.invalidate.ise"));  
      5.         // 明顯的注銷方法  
      6.         expire();  
      7.     }  


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

      Java代碼  收藏代碼
      1. public boolean isValid() {  
      2.         ……  
      3.         //這就是判斷距離上次訪問是否超時的過程  
      4.         if (maxInactiveInterval >= 0) {   
      5.             long timeNow = System.currentTimeMillis();  
      6.             int timeIdle = (int) ((timeNow - thisAccessedTime) / 1000L);  
      7.             if (timeIdle >= maxInactiveInterval) {  
      8.                 expire(true);  
      9.             }  
      10.         }  
      11.         return (this.isValid);  
      12.     }  


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

      Java代碼  收藏代碼
      1. public void expire(boolean notify) {   
      2.   
      3.         synchronized (this) {  
      4.             ......  
      5.             //設(shè)立標志位  
      6.             setValid(false);  
      7.   
      8.             //計算一些統(tǒng)計值,例如此manager下所有session平均存活時間等  
      9.             long timeNow = System.currentTimeMillis();  
      10.             int timeAlive = (int) ((timeNow - creationTime)/1000);  
      11.             synchronized (manager) {  
      12.                 if (timeAlive > manager.getSessionMaxAliveTime()) {  
      13.                     manager.setSessionMaxAliveTime(timeAlive);  
      14.                 }  
      15.                 int numExpired = manager.getExpiredSessions();  
      16.                 numExpired++;  
      17.                 manager.setExpiredSessions(numExpired);  
      18.                 int average = manager.getSessionAverageAliveTime();  
      19.                 average = ((average * (numExpired-1)) + timeAlive)/numExpired;  
      20.                 manager.setSessionAverageAliveTime(average);  
      21.             }  
      22.   
      23.             // 將此session從manager對象的session池中刪除  
      24.             manager.remove(this);  
      25.             ......  
      26.         }  
      27.     }  


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

      Xml代碼  收藏代碼
      1. <session-config>  
      2.     <session-timeout>30</session-timeout>  
      3. </session-config>  


      單位是分鐘。 
      Session持久化及啟動初始化 
      這個功能主要是,當tomcat執(zhí)行安全退出時(通過執(zhí)行shutdown腳本),會將session持久化到本地文件,通常在tomcat的部署目錄下有個session.ser文件。當啟動tomcat時,會從這個文件讀入session,并添加到manager的session池中去。 
      這樣,當tomcat正常重啟時, session沒有丟失,對于用戶而言,體會不到重啟,不影響用戶體驗。 
      看一下概念圖吧,覺得不是重要實現(xiàn)邏輯,代碼就不說了。 
       
      總結(jié) 
      由此可以看出,session的管理是容器層做的事情,應(yīng)用層一般不會參與session的管理,也就是說,如果在應(yīng)用層獲取到相應(yīng)的session,已經(jīng)是由tomcat提供的,因此如果過多的依賴session機制來進行一些操作,例如訪問控制,安全登錄等就不是十分的安全,因為如果有人能得到正在使用的jsessionid,則就可以侵入系統(tǒng)。

      自己的個人博客:bingtel-木猶如此的博客 

       







       

      posted @ 2014-12-28 20:21  bingtel  閱讀(270)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产国语毛片在线看国产| 免费人成网站视频在线观看| 无码中文字幕av免费放| 欧美高清一区三区在线专区| 亚州av第二区国产精品| 狠狠色丁香婷婷综合| 国模雨珍浓密毛大尺度150p | 亚洲AV永久无码嘿嘿嘿嘿| 亚洲男女内射在线播放| 铁岭市| 精品久久丝袜熟女一二三| 精品人妻中文字幕在线| 人妻在线中文字幕| AV无码免费不卡在线观看| 夜夜躁日日躁狠狠久久av| 最好看的中文字幕国语| 日韩精品中文字幕有码| 亚洲熟女一区二区av| 久久日产一线二线三线| 99久久无色码中文字幕| 中文字幕亚洲国产精品| 久久久久人妻一区精品色| 亚洲熟女国产熟女二区三区| 中文午夜乱理片无码| 亚洲中文无码av永久不收费| 亚洲综合国产成人丁香五| 丰满少妇内射一区| 欧美丰满熟妇hdxx| 国产性生大片免费观看性| 亚洲人成色99999在线观看| 久久99精品久久久久久琪琪| 国产欧美在线手机视频| 久久人妻精品大屁股一区| 国产二区三区不卡免费| 国产av午夜精品福利| 尤物yw193无码点击进入| 色又黄又爽18禁免费网站现观看| 久爱www人成免费网站| 亚洲国产成人无码av在线播放| 成人午夜伦理在线观看| 欧美18videosex性欧美黑吊|