<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    stone2083

    Tomcat(6.0.14) Session創建機制簡介

    背景:
    公司的一個web應用,提交給測試部門做壓力測試(由于不是我負責的,不清楚如何做的壓力測試,以及測試指標),結果沒壓多久,就出現OutOfMemory.
    接手協助原因查找,通過監控工具,發現StandardSession(org.apache.catalina.session.StandardSession)對象不斷增長,毫無疑問,肯定是在不斷創建Session對象.
    備注:一般做壓力測試,每次請求都不會指定JESSESIONID值,導致Web容器認為每次請求都是新的請求,于是創建Session對象.
    同事負責代碼Review,發現應用沒有任何一個地方存放Session內容.困惑之...

    問題:Tomcat容器何時創建Session對象?
    想當然認為,只有動態存放Session內容的時候,才會創建Session對象.但是事實真得如此嗎?

    先看Servlet協議描述:
    請看:
    getSession(boolean create)方法:
    javax.servlet.http.HttpServletRequest.getSession(boolean create)

    Returns the current HttpSession associated with this request or, if if there is no current session and create is true, returns a new session. 

    If create is false and the request has no valid HttpSession, this method returns null. 

    To make sure the session is properly maintained, you must call this method before the response is committed.

    簡單地說:當create變量為true時,如果當前Session不存在,創建一個新的Session并且返回.

    getSession()方法:
    javax.servlet.http.HttpSession getSession();

    Returns the current session associated with this request, or if the request does not have a session, creates one.
    簡單的說:當當前Session不存在,創建并且返回.


    所以說,協議規定,在調用getSession方法的時候,就會創建Session對象.



    既然協議這么定了,我們再來看看Tomcat是如何實現的:(下面的描述,是基于Tomcat6.0.14版本源碼)
    先看一張簡單的類圖:


    ApplicationContext:Servlet規范中ServletContext的實現
    StandardContext:Tomcat定義的Context默認實現.維護了一份SessionManager對象,管理Session對象.所有的Session對象都存放在Manager定義的Map<String,Session>容器中.
    StanardManager:標準的Session管理,將Session存放在內容,Web容器關閉的時候,持久化到本地文件
    PersistentManager:持久化實現的Session管理,默認有兩種實現方式:
    --持久化到本地文件
    --持久化到數據庫

    了解了大概的概念后,回頭再來看看org.apache.catalina.connector.Request.getSession()是如何實現的.
    最終調用的是doGetSession(boolean create)方法,請看:
    protected Session doGetSession(boolean create) {

            
    // There cannot be a session if no context has been assigned yet
            if (context == null)
                
    return (null);

            
    // Return the current session if it exists and is valid
            if ((session != null&& !session.isValid())
                session 
    = null;
            
    if (session != null)
                
    return (session);

            
    // Return the requested session if it exists and is valid
            Manager manager = null;
            
    if (context != null)
                manager 
    = context.getManager();
            
    if (manager == null)
                
    return (null);      // Sessions are not supported
            if (requestedSessionId != null) {
                
    try {
                    session 
    = manager.findSession(requestedSessionId);
                } 
    catch (IOException e) {
                    session 
    = null;
                }
                
    if ((session != null&& !session.isValid())
                    session 
    = null;
                
    if (session != null) {
                    session.access();
                    
    return (session);
                }
            }

            
    // Create a new session if requested and the response is not committed
            if (!create)
                
    return (null);
            
    if ((context != null&& (response != null&&
                context.getCookies() 
    &&
                response.getResponse().isCommitted()) {
                
    throw new IllegalStateException
                  (sm.getString(
    "coyoteRequest.sessionCreateCommitted"));
            }

            
    // Attempt to reuse session id if one was submitted in a cookie
            
    // Do not reuse the session id if it is from a URL, to prevent possible
            
    // phishing attacks
            if (connector.getEmptySessionPath() 
                    
    && isRequestedSessionIdFromCookie()) {
                session 
    = manager.createSession(getRequestedSessionId());
            } 
    else {
                session 
    = manager.createSession(null);
            }

            
    // Creating a new session cookie based on that session
            if ((session != null&& (getContext() != null)
                   
    && getContext().getCookies()) {
                Cookie cookie 
    = new Cookie(Globals.SESSION_COOKIE_NAME,
                                           session.getIdInternal());
                configureSessionCookie(cookie);
                response.addCookieInternal(cookie, context.getUseHttpOnly());
            }

            
    if (session != null) {
                session.access();
                
    return (session);
            } 
    else {
                
    return (null);
            }

        }


    至此,簡單地描述了Tomcat Session創建的機制,有興趣的同學要深入了解,不妨看看Tomcat源碼實現.



    補充說明,順便提一下Session的過期策略.
    過期方法在:
    org.apache.catalina.session.ManagerBase(StandardManager基類) processExpires方法:
    public void processExpires() {

            
    long timeNow = System.currentTimeMillis();
            Session sessions[] 
    = findSessions();
            
    int expireHere = 0 ;
            
            
    if(log.isDebugEnabled())
                log.debug(
    "Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length);
            
    for (int i = 0; i < sessions.length; i++) {
                
    if (sessions[i]!=null && !sessions[i].isValid()) {
                    expireHere
    ++;
                }
            }
            
    long timeEnd = System.currentTimeMillis();
            
    if(log.isDebugEnabled())
                 log.debug(
    "End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere);
            processingTime 
    += ( timeEnd - timeNow );

        }

    其中,Session.isValid()方法會做Session的清除工作.


    在org.apache.catalina.core.ContainerBase中,會啟動一個后臺線程,跑一些后臺任務,Session過期任務是其中之一:
    protected void threadStart() {

            
    if (thread != null)
                
    return;
            
    if (backgroundProcessorDelay <= 0)
                
    return;

            threadDone 
    = false;
            String threadName 
    = "ContainerBackgroundProcessor[" + toString() + "]";
            thread 
    = new Thread(new ContainerBackgroundProcessor(), threadName);
            thread.setDaemon(
    true);
            thread.start();

        }


    OVER :)

    posted on 2010-02-26 16:12 stone2083 閱讀(7065) 評論(4)  編輯  收藏 所屬分類: java

    Feedback

    # re: Tomcat(6.0.14) Session創建機制簡介 2010-03-05 17:21 小菜花

    也就是說session對象過多是沒法規避的?  回復  更多評論   

    # re: Tomcat(6.0.14) Session創建機制簡介 2010-03-07 15:30 stone2083

    @小菜花
    準確地講,除非你的應用完全不需要保存狀態(無狀態應用),不然地話,只要有一個新的連接過來,web容器都需要創建Session概念,維護狀態信息.
    但是Session是什么?Session僅僅是一個概念:"Provides a way to identify a user across more than one page request or visit to a Web site and to store information about that user."--簡單地講,保存用戶狀態信息.
    所以說,我們完全可以根據應用的需求,定制Session的實現:
    a. Session保存到JVM內容中--Tomcat默認的實現
    b. Session保存到Cookie中--Cookie-Based Session
    c. Session保存到本地文件--Tomcat提供的非默認實現之一
    d. Session保存到Cache Store中--比如常見的Memcached
    e. Session保存到數據庫中--比如保存到mysql數據庫session表,中間對于活躍的Session 緩存到cached中.
    ......
    那么,假如一個應用有大量一次性不同用戶的請求(僅僅是一次性的,比如上述文章描述的場景),那么選擇c,d,e方案都能有效解決文中所描述的問題.  回復  更多評論   

    # re: Tomcat(6.0.14) Session創建機制簡介 2010-03-07 18:27 小菜花

    @stone2083
    恩,之前我也遇到這個問題,也是性能測試的時候發現內存下不來,后來發現是session對象過多,我們在測試的時候有傳遞sessionid給服務器,后來沒找到為啥還是有過多session的原因,后來不了了之了,因為線上基本上不會出現這種情況  回復  更多評論   

    # re: Tomcat(6.0.14) Session創建機制簡介 2010-06-11 20:23 stone2083

    @小菜花
    理論上來說,傳遞jsessionid,只要value是一致的,服務端不會創建多份session.
    可以在測試環境下通過debug 或者 監控工具,跟蹤下創建多份session的情況.  回復  更多評論   

    主站蜘蛛池模板: 亚洲人成人网站18禁| 亚洲男人的天堂在线播放| 亚洲黄页网在线观看| 99久久人妻精品免费一区| 亚洲精品乱码久久久久久中文字幕 | 91在线视频免费看| 亚洲国产精品综合福利专区| 18观看免费永久视频| 亚洲一区二区电影| 8x成人永久免费视频| 亚洲欧洲校园自拍都市| 成人浮力影院免费看| 亚洲卡一卡二卡乱码新区| 最近中文字幕无吗高清免费视频| 亚洲午夜无码毛片av久久京东热| 大地资源在线观看免费高清| 亚洲国产精品成人综合色在线| 日韩精品视频免费在线观看| 色窝窝亚洲AV网在线观看| 亚洲A丁香五香天堂网| 国产无限免费观看黄网站| 亚洲成a人片在线观看日本| 57pao国产成视频免费播放| 中文字幕乱码亚洲无线三区| 国产无遮挡裸体免费视频| a免费毛片在线播放| 亚洲国产成人精品不卡青青草原| 亚洲w码欧洲s码免费| 亚洲国产精品无码中文lv| av在线亚洲欧洲日产一区二区| 免费国产成人18在线观看| 亚洲中文无码a∨在线观看| 免费无码又爽又刺激毛片| eeuss影院免费直达入口| 久久狠狠高潮亚洲精品| 小小影视日本动漫观看免费| 国精产品一区一区三区免费视频| 亚洲乱码无限2021芒果| 亚洲精品无码成人片在线观看| 亚洲免费视频网站| 亚洲JLZZJLZZ少妇|