10

我想使我在 Tomcat 中的所有会话都过期。我们在 Fitnesse 下测试我们的产品,一些会话仍然存在,会话结束会导致测试之间存在依赖关系。我使用以下代码手动执行此操作,但仍保留一些会话(我可以使用http://localhost:8080/manager/html/list url 检查它)

public static void expireAllSessions() {
    String[] applications = { "a", "b", "c", "d",  "e" };
    for (String application : applications) {
        try {
            expireAllSessions(application);
        } catch (Exception e) {
            logger.error(e);
        }
    }
}

private static void expireAllSessions(final String application) throws Exception {
    // cf doc http://hc.apache.org/httpclient-3.x/authentication.html
    HttpClient client = new HttpClient();
    client.getParams().setAuthenticationPreemptive(true);
    Credentials userPassword = new UsernamePasswordCredentials("tomcat", "tomcat");
    client.getState().setCredentials(AuthScope.ANY, userPassword);

    String url = "http://localhost:8080/manager/html/expire";
    NameValuePair[] parametres = new NameValuePair[] {
            new NameValuePair("path", "/" + application),
            new NameValuePair("idle", "0")
    };
    HttpMethod method = new GetMethod(url);
    method.setQueryString(parametres);
    client.executeMethod(method);
}

有没有办法在没有剩余会话的情况下更有效、更直接地做到这一点?

4

3 回答 3

8

我假设您的应用程序是真正独立的上下文。我已经做了一些类似于你在HttpSessionListener每个上下文中使用的要求的事情。这里棘手的部分是您需要有一个由根类加载器加载的会话集合,而不是上下文类加载器。这就是我的记忆:

创建一个为每个上下文保存活动会话的类。此类必须驻留在 tomcat /lib 目录中,以便每个上下文都可以访问它。它不能是任何上下文的一部分。

public class SessionMap {

  private static Map<ServletContext, Set<HttpSession>> map =
    new HashMap<ServletContext, Set<HttpSession>>();

  private SessionMap() {
  }

  public static Map<ServletContext, Set<HttpSession>> getInstance() {
    return map;
  }

  public static void invalidate(String[] contexts) {
    synchronized (map) {
      List<String> l = Arrays.asList(contexts);     
      for (Map.Entry<ServletContext, Set<HttpSession>> e : map.entrySet()) {
        // context name without the leading slash
        String c = e.getKey().getContextPath().substring(1);
        if (l.contains(c)) {
          for (HttpSession s : e.getValue()) 
            s.invalidate();
        }
      }
    }
  }

}

为每个上下文创建一个监听器。

public class ApplicationContextListener implements HttpSessionListener {

  public void sessionCreated(HttpSessionEvent event) {
    ConcurrentMap<ServletContext, Set<HttpSession>> instance = SessionMap.getInstance();
    synchronized (instance) {
      ServletContext c = event.getSession().getServletContext();
      Set<HttpSession> set = instance.get(c);
      if (c == null) {
        set = new HashSet<HttpSession>();
        instance.put(c, set);
      }
      set.add(event.getSession());
    }
  }

  public void sessionDestroyed(HttpSessionEvent event) {
    ConcurrentMap<ServletContext, Set<HttpSession>> instance = SessionMap.getInstance();
    synchronized (map) {
      ServletContext c = event.getSession().getServletContext();
      Set<HttpSession> set = instance.get(c);
      if (c != null) {
        set.remove(event.getSession());
      }
    }
  }

}

在相应上下文的web.xml.

<listener>
  <listener-class>ApplicationContextListener</listener-class>
</listener>

然后,您可以调用以下行来使任何上下文中的所有内容无效。

SessionMap.invalidate();

为了安全起见,我正在地图上同步。

于 2010-10-19T01:45:09.087 回答
3

您可以使用 HttpSessionListener 将会话的引用保存在数据结构中,然后在闲暇时使用它

于 2010-10-18T16:05:44.220 回答
1

Have you looked at Lamda Probe? For each of your web applications, you can view the contents of the session and expire them (all).

alt text

If you are keen on writing your own app to do this instead; Lamda Probe is open source, so you could take code from them to help accomplish your goal.

于 2010-10-18T18:21:36.797 回答