嵌入式码头:在上下文中显示所有会话
Embedded jetty: display all sessions in context
我最近将一个使用嵌入式 Jetty 的项目从 6.1 版移到了 9.4 版。
这比我预期的要容易。现在只剩下一项功能需要迁移:
该项目有一个管理工具,它显示所有加载的上下文(它可以托管多个 Web 应用程序)并且对于每个上下文,它列出已注册的 HTTP 会话,包括会话属性等。
在 Jetty 6 中,它是这样的:
Handler[] handlers = jettyServer.getHandlers();
for (Handler h : handlers) {
if (h instanceof ContextHandlerCollection) {
ContextHandlerCollection ch = (ContextHandlerCollection) h;
Handler[] contexts = ch.getHandlers();
for (Handler context : contexts) {
if (context instanceof WebAppContext) {
WebAppContext wapp = (WebAppContext) context;
// Here, I am stuck in migrating this to jetty 9:
SessionManager sm = wapp.getSessionHandler().getSessionManager();
if (sm instanceof HashSessionManager) {
HashSessionManager hsm = (HashSessionManager) sm;
Map<?,?> sessions = hsm.getSessionMap();
if (sessions != null) {
for (Map.Entry<?,?> entry : sessions.entrySet()) {
if (entry.getValue() instanceof HttpSession) {
HttpSession s = (HttpSession) entry.getValue();
}
}
}
}
}
}
}
}
新的 Jetty 9 结构有点不同,但我能够访问所有上下文。但是在 Jetty 9 中,我无法从上下文中访问 SessionManager
。
wapp.getSessionHandler().getSessionManager();
不再起作用,SessionHandler
上的 getSessionManager()
方法不再存在。在搜索了几个小时之后,我没有找到任何方法从 WebAppContext
到该上下文中的 HTTPSession
实例。
有人知道怎么去吗?
无法访问活动列表 HttpSession
。
发生此更改是为了支持会话管理的持续改进,以处理分布式 SessionDataStores
和没有会话粘性的分布式服务器(例如许多云产品)
您最好在服务器端跟踪 HttpSessions
自己。
怎么做...
实施自定义会话侦听器。
确保它实现了 javax.servlet.http.HttpSessionListener
和 javax.servlet.http.HttpSessionIdListener
以跟踪创建/销毁/更改的会话。 (可能还想实施 javax.servlet.ServletContextListener
以停止跟踪已销毁上下文中的会话)
确保在此实现中仅通过会话的 ID(以及它们所属的上下文)跟踪会话。 (不要持有对 HttpSession 对象的引用,否则你会搞乱 GC 和 WebApp 生命周期)。
示例:
public static class SessionTracker implements HttpSessionListener,
HttpSessionIdListener, ServletContextListener
{
private final Server server;
private final SessionHandler sessionHandler;
private String contextPath;
private HashSet<String> sessionIds = new HashSet<>();
public SessionTracker(Server server, SessionHandler sessionHandler)
{
this.server = server;
this.sessionHandler = sessionHandler;
this.sessionHandler.addEventListener(this);
}
public String getContextPath()
{
return contextPath;
}
public SessionHandler getSessionHandler()
{
return sessionHandler;
}
public HashSet<String> getSessionIds()
{
return sessionIds;
}
@Override
public void contextInitialized(ServletContextEvent sce)
{
contextPath = sce.getServletContext().getContextPath();
}
@Override
public void contextDestroyed(ServletContextEvent sce)
{
Collection<SessionTracker> trackers = this.server.getBeans(SessionTracker.class);
trackers.removeIf((tracker) -> tracker.getContextPath().equals(sce.getServletContext().getContextPath()));
}
@Override
public void sessionCreated(HttpSessionEvent se)
{
sessionIds.add(se.getSession().getId());
}
@Override
public void sessionDestroyed(HttpSessionEvent se)
{
sessionIds.remove(se.getSession().getId());
}
@Override
public void sessionIdChanged(HttpSessionEvent event, String oldSessionId)
{
sessionIds.add(oldSessionId);
sessionIds.add(event.getSession().getId());
}
}
以及将其正确添加到所有上下文的方法...
// After server.start() somewhere.
addSessionTracker(server.getHandler());
private static void addSessionTracker(Handler handler)
{
if (handler == null)
{
return; // skip
}
if (handler instanceof HandlerCollection)
{
HandlerCollection handlers = (HandlerCollection) handler;
for (Handler child : handlers.getHandlers())
{
addSessionTracker(child);
}
}
else
{
if (handler instanceof ServletContextHandler)
{
ServletContextHandler context = (ServletContextHandler) handler;
SessionHandler sessionHandler = context.getSessionHandler();
new SessionTracker(handler.getServer(), sessionHandler);
}
}
}
然后使用这些追踪器...
private static void doSomethingWithSessionTracker(Server server)
{
Collection<SessionTracker> trackers = server.getBeans(SessionTracker.class);
trackers.forEach((tracker) -> {
tracker.getSessionIds().forEach((sessionId) -> {
Session session = tracker.getSessionHandler().getSession(sessionId);
// Do something with Session.
});
});
}
Note that the above will only show you the Session being tracked on that server, if you have multiple servers, or a distributed Session store, you wont see the Sessions from other servers.
If this is important to you, consider writing your own SessionDataStore
that lets you access the stored Sessions
.
我最近将一个使用嵌入式 Jetty 的项目从 6.1 版移到了 9.4 版。 这比我预期的要容易。现在只剩下一项功能需要迁移: 该项目有一个管理工具,它显示所有加载的上下文(它可以托管多个 Web 应用程序)并且对于每个上下文,它列出已注册的 HTTP 会话,包括会话属性等。 在 Jetty 6 中,它是这样的:
Handler[] handlers = jettyServer.getHandlers();
for (Handler h : handlers) {
if (h instanceof ContextHandlerCollection) {
ContextHandlerCollection ch = (ContextHandlerCollection) h;
Handler[] contexts = ch.getHandlers();
for (Handler context : contexts) {
if (context instanceof WebAppContext) {
WebAppContext wapp = (WebAppContext) context;
// Here, I am stuck in migrating this to jetty 9:
SessionManager sm = wapp.getSessionHandler().getSessionManager();
if (sm instanceof HashSessionManager) {
HashSessionManager hsm = (HashSessionManager) sm;
Map<?,?> sessions = hsm.getSessionMap();
if (sessions != null) {
for (Map.Entry<?,?> entry : sessions.entrySet()) {
if (entry.getValue() instanceof HttpSession) {
HttpSession s = (HttpSession) entry.getValue();
}
}
}
}
}
}
}
}
新的 Jetty 9 结构有点不同,但我能够访问所有上下文。但是在 Jetty 9 中,我无法从上下文中访问 SessionManager
。
wapp.getSessionHandler().getSessionManager();
不再起作用,SessionHandler
上的 getSessionManager()
方法不再存在。在搜索了几个小时之后,我没有找到任何方法从 WebAppContext
到该上下文中的 HTTPSession
实例。
有人知道怎么去吗?
无法访问活动列表 HttpSession
。
发生此更改是为了支持会话管理的持续改进,以处理分布式 SessionDataStores
和没有会话粘性的分布式服务器(例如许多云产品)
您最好在服务器端跟踪 HttpSessions
自己。
怎么做...
实施自定义会话侦听器。
确保它实现了 javax.servlet.http.HttpSessionListener
和 javax.servlet.http.HttpSessionIdListener
以跟踪创建/销毁/更改的会话。 (可能还想实施 javax.servlet.ServletContextListener
以停止跟踪已销毁上下文中的会话)
确保在此实现中仅通过会话的 ID(以及它们所属的上下文)跟踪会话。 (不要持有对 HttpSession 对象的引用,否则你会搞乱 GC 和 WebApp 生命周期)。
示例:
public static class SessionTracker implements HttpSessionListener,
HttpSessionIdListener, ServletContextListener
{
private final Server server;
private final SessionHandler sessionHandler;
private String contextPath;
private HashSet<String> sessionIds = new HashSet<>();
public SessionTracker(Server server, SessionHandler sessionHandler)
{
this.server = server;
this.sessionHandler = sessionHandler;
this.sessionHandler.addEventListener(this);
}
public String getContextPath()
{
return contextPath;
}
public SessionHandler getSessionHandler()
{
return sessionHandler;
}
public HashSet<String> getSessionIds()
{
return sessionIds;
}
@Override
public void contextInitialized(ServletContextEvent sce)
{
contextPath = sce.getServletContext().getContextPath();
}
@Override
public void contextDestroyed(ServletContextEvent sce)
{
Collection<SessionTracker> trackers = this.server.getBeans(SessionTracker.class);
trackers.removeIf((tracker) -> tracker.getContextPath().equals(sce.getServletContext().getContextPath()));
}
@Override
public void sessionCreated(HttpSessionEvent se)
{
sessionIds.add(se.getSession().getId());
}
@Override
public void sessionDestroyed(HttpSessionEvent se)
{
sessionIds.remove(se.getSession().getId());
}
@Override
public void sessionIdChanged(HttpSessionEvent event, String oldSessionId)
{
sessionIds.add(oldSessionId);
sessionIds.add(event.getSession().getId());
}
}
以及将其正确添加到所有上下文的方法...
// After server.start() somewhere.
addSessionTracker(server.getHandler());
private static void addSessionTracker(Handler handler)
{
if (handler == null)
{
return; // skip
}
if (handler instanceof HandlerCollection)
{
HandlerCollection handlers = (HandlerCollection) handler;
for (Handler child : handlers.getHandlers())
{
addSessionTracker(child);
}
}
else
{
if (handler instanceof ServletContextHandler)
{
ServletContextHandler context = (ServletContextHandler) handler;
SessionHandler sessionHandler = context.getSessionHandler();
new SessionTracker(handler.getServer(), sessionHandler);
}
}
}
然后使用这些追踪器...
private static void doSomethingWithSessionTracker(Server server)
{
Collection<SessionTracker> trackers = server.getBeans(SessionTracker.class);
trackers.forEach((tracker) -> {
tracker.getSessionIds().forEach((sessionId) -> {
Session session = tracker.getSessionHandler().getSession(sessionId);
// Do something with Session.
});
});
}
Note that the above will only show you the Session being tracked on that server, if you have multiple servers, or a distributed Session store, you wont see the Sessions from other servers. If this is important to you, consider writing your own
SessionDataStore
that lets you access the storedSessions
.