Tomcat中的session實現

FrankYou發表於2018-05-21

Tomcat中一個會話對應一個session,其實現類是StandardSession,檢視原始碼,可以找到一個attributes成員屬性,即儲存session的資料結構,為ConcurrentHashMap,支援高併發的HashMap實現;

/**
* The collection of user data attributes associated with this Session.
*/
protected Map<String, Object> attributes = new ConcurrentHashMap<String, Object>();

那麼,tomcat中多個會話對應的session是由誰來維護的呢?ManagerBase類,檢視其程式碼,可以發現其有一個sessions成員屬性,儲存著各個會話的session資訊:

/**
    * The set of currently active Sessions for this Manager, keyed by
    * session identifier.
    */
protected Map<String, Session> sessions = new ConcurrentHashMap<String, Session>();

接下來,看一下幾個重要的方法,

伺服器查詢Session物件的方法

客戶端每次的請求,tomcat都會在HashMap中查詢對應的key為JSESSIONID的Session物件是否存在,可以檢視Request的doGetSession方法原始碼,如下原始碼:

先看doGetSession方法中的如下程式碼,這個一般是第一次訪問的情況,即建立session物件,session的建立是呼叫了ManagerBase的createSession方法來實現的; 另外,注意response.addSessionCookieInternal方法,該方法的功能就是上面提到的往響應頭寫入“Set-Cookie”資訊;最後,還要呼叫session.access方法記錄下該session的最後訪問時間,因為session是可以設定過期時間的

session = manager.createSession(sessionId);

// Creating a new session cookie based on that session
if ((session != null) && (getContext() != null)
        && getContext().getServletContext().
                getEffectiveSessionTrackingModes().contains(
                        SessionTrackingMode.COOKIE)) {
    Cookie cookie =
        ApplicationSessionCookieConfig.createSessionCookie(
                context, session.getIdInternal(), isSecure());

    response.addSessionCookieInternal(cookie);
}

if (session == null) {
    return null;
}

session.access();
return session;

再看doGetSession方法中的如下程式碼,這個一般是第二次以後訪問的情況,通過ManagerBase的findSession方法查詢session,其實就是利用map的key從ConcurrentHashMap中拿取對應的value,這裡的key即requestedSessionId,也即JSESSIONID,同時還要呼叫session.access方法,記錄下該session的最後訪問時間;

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);
    }
}

在session物件中查詢和設定key-value的方法

這個我們一般呼叫getAttribute/setAttribute方法:

getAttribute方法很簡單,就是根據key從map中獲取value;

setAttribute方法稍微複雜點,除了設定key-value外,如果新增了一些事件監聽(HttpSessionAttributeListener)的話,還要通知執行,如beforeSessionAttributeReplaced, afterSessionAttributeReplaced, beforeSessionAttributeAdded、 afterSessionAttributeAdded。。。

相關文章