我有一个任务,向站点管理员显示用户名列表以及每个用户当前使用多少个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