整個創建 Session 的過程比較簡單,就是實例化 StandardSession 對象並設置其基本屬性,以及生成唯一的 sessionId,其次就是記錄創建時間,關鍵代碼如下所示:
在 tomcat 中是可以限制 session 數量的,如果需要限制,請指定 Manager 的 maxActiveSessions 參數,默認不做限制,不建議進行設置,但是如果存在惡意攻擊,每次請求不攜帶 Cookie 就有可能會頻繁創建 Session,導致 Session 對象爆滿最終出現 OOM。另外 sessionId 採用隨機演算法生成,並且每次生成都會判斷當前是否已經存在該 id,從而避免 sessionId 重複。而 StandardManager 是使用 ConcurrentHashMap 存儲 session 對象的,sessionId 作為 key,org.apache.catalina.Session 作為 value。此外,值得注意的是 StandardManager 創建的是 tomcat 的 org.apache.catalina.session.StandardSession,同時他也實現了 servlet 的 HttpSession,但是為了安全起見,tomcat 並不會把這個 StandardSession 直接交給應用程序,因此需要調用 org.apache.catalina.Session#getSession() 獲取 HttpSession。
前面我們分析了 Session 的創建過程,而 Session 會話是有時效性的,下面我們來看下 tomcat 是如何進行失效檢查的。在分析之前,我們先回顧下 Container 容器的 Background 線程。
tomcat 所有容器組件,都是繼承至 ContainerBase 的,包括 StandardEngine、StandardHost、StandardContext、StandardWrapper,而 ContainerBase 在啟動的時候,如果 backgroundProcessorDelay 參數大於 0 則會開啟 ContainerBackgroundProcessor 後臺線程,調用自己以及子容器的 backgroundProcess 進行一些後臺邏輯的處理,和 Lifecycle 一樣,這個動作是具有傳遞性的,也就是說子容器還會把這個動作傳遞給自己的子容器,如下圖所示,其中父容器會遍歷所有的子容器並調用其 backgroundProcess 方法,而 StandardContext 重寫了該方法,它會調用 StandardManager#backgroundProcess() 進而完成 Session 的清理工作。看到這裡,不得不感慨 tomcat 的責任