我有一個任務,向站點管理員顯示用戶名列表以及每個用戶當前使用多少個Tomcat會話(以及一些其他支持相關信息)。Tomcat中的Http Sessions生命週期
我保持身份驗證用戶作爲應用程序上下文屬性如下(省略不必要的細節)。
Hashtable<String, UserInfo> logins //maps login to UserInfo
其中的UserInfo被定義爲
class UserInfo implements Serializable {
String login;
private transient Map<HttpSession, String> sessions =
Collections.synchronizedMap(
new WeakHashMap<HttpSession, String>() //maps session to sessionId
);
...
}
每個成功登錄存儲會話到這個sessions
地圖。 我的HttpSessionsListener
實現sessionDestroyed()
從此映射中刪除銷燬的會話,並且如果sessions.size()== 0從logins
中刪除UserInfo。
我有時會有0個會話顯示給某些用戶。同行評審和單元測試表明代碼是正確的。所有會話都是可序列化的。
Tomcat是否有可能將會話從內存卸載到硬盤驅動器,例如,當有一段時間不活動(會話超時設置爲40分鐘)?有沒有其他的場景會議從GC的角度來看是「丟失」的,但是HttpSessionsListener.sessionDestroyed()沒有被調用?
J2SE 6,Tomcat 6或7 standalone,行爲在任何操作系統上都是一致的。
ConcurrentHashMap是個不錯的主意。沒有什麼理由,只是一些遺留的考慮,不應再相關。我不認爲涉及的服務器重新啓動,但我會仔細檢查 - 我的會話畢竟是暫時的。無論如何我必須解決這個問題,如果你是對的,我會標記你的答案。 – 2011-04-14 14:10:35
是什麼讓你認爲你是HttpSession的瞬態?會話映射上的transient修飾符似乎是多餘的,因爲UserInfo類沒有實現Serializable(這是混淆的地方嗎?)。而後來認爲HttpSession作爲一個映射關鍵字並不完全正確,因此它的equals()和hashcode()依賴於Tomcat(或其他應用服務器)選擇的實現。將交換密鑰作爲會話ID和值作爲HttpSession將會更好。 – martin 2011-04-14 20:38:25
UserInfo實現了Serializable,因爲這個Web應用程序可以在HA集羣中工作,並在不刪除會話(也需要序列化應用程序上下文屬性)的情況下「繼續」重新啓動。在代碼示例中省略它是我的錯誤。 – 2011-04-20 17:02:06