52

假设我有一个正在运行的基于 Java 的 Web 应用程序,其中有 0 个或多个HttpSession与之关联的有效对象。我想要一种访问当前有效HttpSession对象列表的方法。我在想我可以实现一个HttpSessionListener并使用它来附加到存储在应用程序范围属性中的会话 id 值列表,但是当会话无效并且谁知道是什么时,我会更新列表别的。

在我开始编写自己的解决方案之前,我想我应该问一个问题:
servlet API 是否提供了一些方法来访问未失效会话对象的完整列表?

我使用 Tomcat 6.x 作为我的 Web 应用程序容器和 MyFaces 1.2.x (JSF) 库。

解决方案
我采用了类似于 BalusC 在这些现有问题中讨论的方法:

我按SessionData类修改来实现HttpSessionBindingListener. 当绑定事件发生时,对象将从所有SessionData对象的集合中添加或删除自己。

@Override
public void valueBound(HttpSessionBindingEvent event) { 
    // Get my custom application-scoped attribute
    ApplicationData applicationData = getApplicationData();
    // Get the set of all SessionData objects and add myself to it
    Set<SessionData> activeSessions = applicationData.getActiveSessions();
    if (!activeSessions.contains(this)) {
        activeSessions.add(this);
    }
}

@Override
public void valueUnbound(HttpSessionBindingEvent event) {
    HttpSession session = event.getSession();
    ApplicationData applicationData = getApplicationData();
    Set<SessionData> activeSessions = applicationData.getActiveSessions();
    if (activeSessions.contains(this)) {
        activeSessions.remove(this);
    }
}

继续激怒我的一件事是 Tomcat 重新启动时会发生什么。除非 Tomcat 已正确配置为不将会话序列化到磁盘,否则它将这样做。当 Tomcat 再次启动时,HttpSession对象(SessionData以及与它们一起的对象)被反序列化,并且会话再次有效。但是,序列化/反序列化完全回避了HttpSession侦听器事件,因此我没有机会SessionData在重新启动后优雅地将反序列化引用放在我的托管对象集中。

我对客户组织中 Tomcat 的生产配置没有任何控制权,因此我不能假设它会按照我期望的方式完成。

我的解决方法是将HttpSession创建时间与收到请求时的应用程序启动时间进行比较。如果会话是在应用程序启动时间之前创建的,那么我会调用invalidate()并将用户发送到错误/警告页面,并解释所发生的事情。

我通过在侦听ServletContextListener器的方法中实现 a 并将当前时间存储在应用程序范围的对象中来获取应用程序启动时间。contextInitialized()

4

3 回答 3

47

不,Servlet API 没有提供方法。你真的必须在HttpSessionListener. 您可以在以下答案中找到几个示例:

于 2010-09-22T15:53:37.753 回答
9

没有直接的方法。这取决于部署。一旦您决定引入分布式部署和负载平衡,上述方法将失败。

于 2010-09-24T14:01:40.330 回答
1

不是一个真正的答案,但在过去的好日子里有“javax.servlet.http.HttpSessionContext”,但它从 2.1 版开始被删除,明确地没有替代:https ://tomcat.apache.org/tomcat- 5.5-doc/servletapi/javax/servlet/http/HttpSessionContext.html

于 2015-12-07T19:05:50.270 回答