Tomcat源码分析-Session源码解析
创始人
2024-05-30 22:44:00
0

tomcat session 设计分析

tomcat session 组件图如下所示,其中 Context 对应一个 webapp 应用,每个 webapp 有多个 HttpSessionListener, 并且每个应用的 session 是独立管理的,而 session 的创建、销毁由 Manager 组件完成,它内部维护了 N 个 Session 实例对象。在前面的文章中,我们分析了 Context 组件,它的默认实现是 StandardContext,它与 Manager 是一对一的关系,Manager 创建、销毁会话时,需要借助 StandardContext 获取 HttpSessionListener 列表并进行事件通知,而 StandardContext 的后台线程会对 Manager 进行过期 Session 的清理工作

org.apache.catalina.Manager 接口的主要方法如下所示,它提供了 Contextorg.apache.catalina.SessionIdGenerator 的 getter/setter 接口,以及创建、添加、移除、查找、遍历 Session 的 API 接口,此外还提供了 Session 持久化的接口(load/unload) 用于加载/卸载会话信息,当然持久化要看不同的实现类

public interface Manager {public Context getContext();public void setContext(Context context);public SessionIdGenerator getSessionIdGenerator();public void setSessionIdGenerator(SessionIdGenerator sessionIdGenerator);public void add(Session session);public void addPropertyChangeListener(PropertyChangeListener listener);public void changeSessionId(Session session);public void changeSessionId(Session session, String newId);public Session createEmptySession();public Session createSession(String sessionId);public Session findSession(String id) throws IOException;public Session[] findSessions();public void remove(Session session);public void remove(Session session, boolean update);public void removePropertyChangeListener(PropertyChangeListener listener);public void unload() throws IOException;public void backgroundProcess();public boolean willAttributeDistribute(String name, Object value);

tomcat8.5 提供了 4 种实现,默认使用 StandardManager,tomcat 还提供了集群会话的解决方案,但是在实际项目中很少运用,关于 Manager 的详细配置信息请参考 tomcat 官方文档

  • StandardManager:Manager 默认实现,在内存中管理 session,宕机将导致 session 丢失;但是当调用 Lifecycle 的 start/stop 接口时,将采用 jdk 序列化保存 Session 信息,因此当 tomcat 发现某个应用的文件有变更进行 reload 操作时,这种情况下不会丢失 Session 信息
  • DeltaManager:增量 Session 管理器,用于Tomcat集群的会话管理器,某个节点变更 Session 信息都会同步到集群中的所有节点,这样可以保证 Session 信息的实时性,但是这样会带来较大的网络开销
  • BackupManager:用于 Tomcat 集群的会话管理器,与DeltaManager不同的是,某个节点变更 Session 信息的改变只会同步给集群中的另一个 backup 节点
  • PersistentManager:当会话长时间空闲时,将会把 Session 信息写入磁盘,从而限制内存中的活动会话数量;此外,它还支持容错,会定期将内存中的 Session 信息备份到磁盘

Session 相关的类图如下所示,StandardSession 同时实现了 javax.servlet.http.HttpSessionorg.apache.catalina.Session 接口,并且对外提供的是 StandardSessionFacade 外观类,保证了 StandardSession 的安全,避免开发人员调用其内部方法进行不当操作。而 org.apache.catalina.connector.Request 实现了 javax.servlet.http.HttpServletRequest 接口,它持有 StandardSession 的引用,对外也是暴露 RequestFacade 外观类。而 StandardManager 内部维护了其创建的 StandardSession,是一对多的关系,并且持有 StandardContext 的引用,而 StandardContext 内部注册了 webapp 所有的 HttpSessionListener 实例。

创建Session

我们以 HttpServletRequest#getSession() 作为切入点,对 Session 的创建过程进行分析

public class SessionExample extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException, ServletException  {HttpSession session = request.getSession();// other code......}

整个流程图如下图所示(查看原图):

tomcat 创建 session 的流程如上图所示,我们的应用程序拿到的 HttpServletRequest 是 org.apache.catalina.connector.RequestFacade(除非某些 Filter 进行了特殊处理),它是 org.apache.catalina.connector.Request 的门面模式。首先,会判断 Request 对象中是否存在 Session,如果存在并且未失效则直接返回,因为在 tomcat 中 Request 对象是被重复利用的,只会替换部分组件,所以会进行这步判断。此时,如果不存在 Session,则尝试根据 requestedSessionId 查找 Session,而该 requestedSessionId 会在 HTTP Connector 中进行赋值(如果存在的话),如果存在 Session 的话则直接返回,如果不存在的话,则创建新的 Session,并且把 sessionId 添加到 Cookie 中,后续的请求便会携带该 Cookie,这样便可以根据 Cookie 中的sessionId 找到原来创建的 Session 了

在上面的过程中,Session 的查找、创建都是由 Manager 完成的,下面我们分析下 StandardManager 创建 Session 的具体逻辑。首先,我们来看下 StandardManager 的类图,它也是个 Lifecycle 组件,并且 ManagerBase 实现了主要的逻辑。

整个创建 Session 的过程比较简单,就是实例化 StandardSession 对象并设置其基本属性,以及生成唯一的 sessionId,其次就是记录创建时间,关键代码如下所示:

public Session createSession(String sessionId) {// 限制 session 数量,默认不做限制,maxActiveSessions = -1if ((maxActiveSessions >= 0) &&(getActiveSessions() >= maxActiveSessions)) {rejectedSessions++;throw new TooManyActiveSessionsException(sm.getString("managerBase.createSession.ise"), maxActiveSessions);}// 创建 StandardSession 实例,子类可以重写该方法Session session = createEmptySession();// 设置属性,包括创建时间,最大失效时间session.setNew(true);session.setValid(true);session.setCreationTime(System.currentTimeMillis());// 设置最大不活跃时间(单位s),如果超过这个时间,仍然没有请求的话该Session将会失效session.setMaxInactiveInterval(getContext().getSessionTimeout() * 60);String id = sessionId;if (id == null) {id = generateSessionId();}session.setId(id);sessionCounter++;   // 这个地方不是线程安全的,可能当时开发人员认为计数器不要求那么准确// 将创建时间添加到LinkedList中,并且把最先添加的时间移除,主要还是方便清理过期sessionSessionTiming timing = new SessionTiming(session.getCreationTime(), 0);synchronized (sessionCreationTiming) {sessionCreationTiming.add(timing);sessionCreationTiming.poll();}return (session);

在 tomcat 中是可以限制 session 数量的,如果需要限制,请指定 Manager 的 maxActiveSessions 参数,默认不做限制,不建议进行设置,但是如果存在恶意攻击,每次请求不携带 Cookie 就有可能会频繁创建 Session,导致 Session 对象爆满最终出现 OOM。另外 sessionId 采用随机算法生成,并且每次生成都会判断当前是否已经存在该 id,从而避免 sessionId 重复。而 StandardManager 是使用 ConcurrentHashMap 存储 session 对象的,sessionId 作为 key,org.apache.catalina.Session 作为 value。此外,值得注意的是 StandardManager 创建的是 tomcat 的 org.apache.catalina.session.StandardSession,同时他也实现了 servlet 的 HttpSession,但是为了安全起见,tomcat 并不会把这个 StandardSession 直接交给应用程序,因此需要调用 org.apache.catalina.Session#getSession() 获取 HttpSession

我们再来看看 StandardSession 的内部结构

  • attributes:使用 ConcurrentHashMap 解决多线程读写的并发问题
  • creationTime:Session 的创建时间
  • expiring:用于标识 Session 是否过期
  • lastAccessedTime:上一次访问的时间,用于计算 Session 的过期时间
  • maxInactiveInterval:Session 的最大存活时间,如果超过这个时间没有请求,Session 就会被清理、
  • listeners:这是 tomcat 的 SessionListener,并不是 servlet 的 HttpSessionListener
  • facade:HttpSession 的外观模式,应用程序拿到的是该对象

相关内容

热门资讯

武陵山天空被鸟群刷屏 转自:JSTV荔枝视频 【#武陵山天空被鸟群刷屏#】眼下...
河南鹤壁有人下河摸金摸铜钱?当... 近日,有网民发布视频称,位于河南省鹤壁市浚县新镇镇卫河流域,有人下河摸金摸铜钱,引发关注。视频显示,...
大连西山水库出现成群黑色大鱼,... 来源:半岛晨报 5月6日下午,市民王先生在大连西山水库发现一群体型较大、通体黝黑的无鳞怪鱼,经专家鉴...
助力工业精神传承,培养创新型人... 5月10日,记者从柳州市教育局获悉,为了更好地将工匠精神、实业报国融入思想政治教育,柳州将打造大中小...
牌桌上的美丽绽放——欧碧奴美容... 转自:衡水日报2025年5月9日,成都青白江东方欲晓十五里休闲中心,160位欧碧奴会员姐姐与亲友闺蜜...
婚姻登记“全国通办”政策问答 来源:“中国民政”微信公号5月10日,新修订的《婚姻登记条例》正式施行,婚姻登记实现“全国通办”。为...
强对流天气致墙体倒塌 3人死亡... 来源:国家应急广播 近日广西百色有网友称参加葬礼时遭遇强对流天气墙体倒塌致多人死伤相关话题冲上社交平...
珍酒李渡举行2024年度股东周... 5月9日,珍酒李渡集团2024年度股东周年大会暨投资者交流会在湖南长沙1912珍酒美食研究所举行,股...
全国仅12个入选!梧州六堡茶国... 转自:梧州发布日前,国家知识产权局公布第一批国家地理标志保护示范区典型案例,全国仅12个保护示范区入...
美业全新动态:杭州美莱受邀出席... 转自:蚌埠新闻网2025年5月7日,杭州美莱受邀亮相2025中国时尚美学盛典Moly Gala,以"...
青年与城市如何共成长?50人论... 来源:中国新闻网 中新网上海5月10日电 题:青年与城市如何共成长?50人论坛交出“上海答卷”作者 ...
葬礼上再发惨剧!3人确认死亡,... 近日,广西百色网友称,参加葬礼遇强对流天气,墙体倒塌致多人死伤。韦女士接受记者采访时表示,近日与家人...
国海证券原总裁意外离世!年61... (转自:金融街1号狙击手)5月10日,据券商中国报道,国海证券原总裁齐国旗近日因遭遇交通意外,不幸离...
永达股份:子公司部分产品应用于... 永达股份(001239)5月9日在业绩说明会上表示,公司控股子公司江苏金源高端装备有限公司部分产品应...
永远不能忘却的纪念(今日谈) 来源:人民日报80年前的伟大胜利打败了不可一世的法西斯势力,带给世人恒久的启迪:光明必将驱散黑暗,正...
社工“寻味儿”救场避免险情   本报讯(实习记者侯国棣)近日,平谷区滨河街道南小区社区84岁的李大爷忘记了厨房正在煮饭的锅,把锅...
美元贬值,这次不一样 美国总统特朗普经常说希望美元贬值。在他看来,这可以降低制造业出口成本,从而促进出口,帮助减少美国巨额...
张本智和:深受雨果世界杯夺冠冲... 来源:九派新闻 近日,日本乒乓球队举行多哈世乒赛赛前新闻发布会,日本男乒选手张本智和在接受采访时谈到...
具茨山原来是中华文明的C位 【#具茨山原来是中华文明的C位#】具茨山位于黄帝故里河南新郑西南,属中岳嵩山东南余脉,东西延绵约40...
李姓股民向ST东时发起索赔 刘...   受损股民可至Hehson股民维权平台登记该公司维权:http://wq.finance.sina...