首页服务器Web服务器 浅谈Tomcat Session管理分析

浅谈Tomcat Session管理分析

前言 在上文Nginx+Tomcat关于Session的管理中简单介绍了如何使用redis来集中管理session,本文首先将介绍默认的管理器是如何管理Session的生命周期的,然后在此基础上对Redis…

前言

在上文Nginx+Tomcat关于Session的管理中简单介绍了如何使用redis来集中管理session,本文首先将介绍默认的管理器是如何管理Session的生命周期的,然后在此基础上对Redis集中式管理Session进行分析。

Tomcat Manager介绍

上文中在Tomcat的context.xml中配置了Session管理器RedisSessionManager,实现了通过redis来存储session的功能;Tomcat本身提供了多种Session管理器,如下类图:

Tomcat,Session

1.Manager接口类

定义了用来管理session的基本接口,包括:createSession,findSession,add,remove等对session操作的方法;还有getMaxActive,setMaxActive,getActiveSessions活跃会话的管理;还有Session有效期的接口;以及与Container相关联的接口;

2.ManagerBase抽象类

实现了Manager接口,提供了基本的功能,使用ConcurrentHashMap存放session,提供了对session的create,find,add,remove功能,并且在createSession中了使用类SessionIdGenerator来生成会话id,作为session的唯一标识;

3.ClusterManager接口类

实现了Manager接口,集群session的管理器,Tomcat内置的集群服务器之间的session复制功能;

4.ClusterManagerBase抽象类

继承了ManagerBase抽象类,实现ClusterManager接口类,实现session复制基本功能;

5.PersistentManagerBase抽象类

继承了ManagerBase抽象类,实现了session管理器持久化的基本功能;内部有一个Store存储类,具体实现有:FileStore和JDBCStore;

6.StandardManager类

继承ManagerBase抽象类,Tomcat默认的Session管理器(单机版);对session提供了持久化功能,tomcat关闭的时候会将session保存到javax.servlet.context.tempdir路径下的SESSIONS.ser文件中,启动的时候会从此文件中加载session;

7.PersistentManager类

继承PersistentManagerBase抽象类,如果session空闲时间过长,将空闲session转换为存储,所以在findsession时会首先从内存中获取session,获取不到会多一步到store中获取,这也是PersistentManager类和StandardManager类的区别;

8.DeltaManager类

继承ClusterManagerBase,每一个节点session发生变更(增删改),都会通知其他所有节点,其他所有节点进行更新操作,任何一个session在每个节点都有备份;

9.BackupManager类

继承ClusterManagerBase,会话数据只有一个备份节点,这个备份节点的位置集群中所有节点都可见;相比较DeltaManager数据传输量较小,当集群规模比较大时DeltaManager的数据传输量会非常大;

10.RedisSessionManager类

继承ManagerBase抽象类,非Tomcat内置的管理器,使用redis集中存储session,省去了节点之间的session复制,依赖redis的可靠性,比起sessin复制扩展性更好;

Session的生命周期

1.解析获取requestedSessionId

当我们在类中通过request.getSession()时,tomcat是如何处理的,可以查看Request中的doGetSession方法:

protected Session doGetSession(boolean create) {   // There cannot be a session if no context has been assigned yet  Context context = getContext();  if (context == null) {    return (null);  }   // Return the current session if it exists and is valid  if ((session != null) && !session.isValid()) {    session = null;  }  if (session != null) {    return (session);  }   // Return the requested session if it exists and is valid  Manager manager = context.getManager();  if (manager == null) {    return null;    // Sessions are not supported  }  if (requestedSessionId != null) {    try {      session = manager.findSession(requestedSessionId);    } catch (IOException e) {      session = null;    }    if ((session != null) && !session.isValid()) {      session = null;    }    if (session != null) {      session.access();      return (session);    }  }   // Create a new session if requested and the response is not committed  if (!create) {    return (null);  }  if ((response != null) &&      context.getServletContext().getEffectiveSessionTrackingModes().      contains(SessionTrackingMode.COOKIE) &&      response.getResponse().isCommitted()) {    throw new IllegalStateException    (sm.getString("coyoteRequest.sessionCreateCommitted"));  }   // Re-use session IDs provided by the client in very limited  // circumstances.  String sessionId = getRequestedSessionId();  if (requestedSessionSSL) {    // If the session ID has been obtained from the SSL handshake then    // use it.  } else if (("/".equals(context.getSessionCookiePath())      && isRequestedSessionIdFromCookie())) {    /* This is the common(ish) use case: using the same session ID with     * multiple web applications on the same host. Typically this is     * used by Portlet implementations. It only works if sessions are     * tracked via cookies. The cookie must have a path of "/" else it     * won't be provided for requests to all web applications.     *     * Any session ID provided by the client should be for a session     * that already exists somewhere on the host. Check if the context     * is configured for this to be confirmed.     */    if (context.getValidateClientProvidedNewSessionId()) {      boolean found = false;      for (Container container : getHost().findChildren()) {        Manager m = ((Context) container).getManager();        if (m != null) {          try {            if (m.findSession(sessionId) != null) {              found = true;              break;            }          } catch (IOException e) {            // Ignore. Problems with this manager will be            // handled elsewhere.          }        }      }      if (!found) {        sessionId = null;      }    }  } else {    sessionId = null;  }  session = manager.createSession(sessionId);   // Creating a new session cookie based on that session  if ((session != null) && (getContext() != null)      && getContext().getServletContext().      getEffectiveSessionTrackingModes().contains(          SessionTrackingMode.COOKIE)) {    Cookie cookie =        ApplicationSessionCookieConfig.createSessionCookie(            context, session.getIdInternal(), isSecure());     response.addSessionCookieInternal(cookie);  }   if (session == null) {    return null;  }   session.access();  return session;}
本文来自网络,不代表1号站长-站长学院|资讯交流平台立场。转载请注明出处: https://www.1cn.cc/fwq/web/3984.html
上一篇centos安装jdk1.8时出现没有/lib/ld-linux.so.2:这个文件的原因分析
下一篇 如何清理docker产生的垃圾文件
admin

作者: admin

这里可以再内容模板定义一些文字和说明,也可以调用对应作者的简介!或者做一些网站的描述之类的文字或者HTML!

为您推荐

评论列表()

    联系我们

    联系我们

    0898-88888888

    在线咨询: QQ交谈

    邮箱: email@wangzhan.com

    工作时间:周一至周五,9:00-17:30,节假日休息

    关注微信
    微信扫一扫关注我们

    微信扫一扫关注我们

    关注微博
    返回顶部