前言

偶然发现Tomcat会话时间的半小时,并不是说“会话创建后只有半小时的有效使用时间”,而是说“会话空闲半小时后会被删除”。索性就翻了一下源码。做了一番整理。

注:空闲时间,指的是同一个会话两次请求之间的间隔时间

Session相关类图

  • HttpSession就是大家Servlet层可以直接使用的Session.
  • Session是Tomcat内部使用的接口,可以做一些内部调用
  • StandardSession是标准的HttpSession实现,同时它也实现了Session接口,用于Tomcat内部管理
  • StandardSessionFacade,类名已经指明它就是一个“门面类”,它内部会引用一个StandardSession的对象,但对外只提供HttpSession规定的方法。

Manager相关类图

StandardManager与PersitentManager都是Manager的实现,但是它们在存储Session对象的方式上有所不同。

StandarManager

1.Tomcat运行时,把Session存储在内存中

2.Tomcat关闭时(注意是正常的关闭操作,如执行stop.sh,而非突然崩溃),会把Session写入到磁盘中,等到Tomcat重启后再把Session加载进来

PersistentManager

1.总是把Session存储在磁盘中。

Manager与Context的关系

在Tomcat中,一个Context就是部署到Tomcat中的一个应用(Webapp)。每一个Context都有一个单独的Manager对象来管理这个应用的会话信息。

Manager如何存储Session

Manager对象会使用一个Map来存储Session对象

  • Key  => SessionId
  • Value  => Session Object
  1. /**
  2. * The set of currently active Sessions for this Manager, keyed by
  3. * session identifier.
  4. */
  5. protected Map<String, Session> sessions = new ConcurrentHashMap<>();

当一个请求到达Context的时候,如果它带有JSESSIONID的Cookie,Manager就能依此找到关联的Session对象,放入到Request对象中。

Manager的定期检查

Manager接口有一个backgroundProcess()方法,顾名思义就是后台处理。

  1. /**
  2. * This method will be invoked by the context/container on a periodic
  3. * basis and allows the manager to implement
  4. * a method that executes periodic tasks, such as expiring sessions etc.
  5. */
  6. public void backgroundProcess();

注:Container接口也有这个方法,这个方法一般在容器启动(start)的时候,开启一个额外的线程来循环执行这个backgroundProcess方法。Context的这个方法启动后,会执行Loader和Manager的backgroundProcess方法。

我们来看看这个方法都做了些什么?

  1. /**
  2. * {@inheritDoc}
  3. * <p>
  4. * Direct call to {@link #processExpires()}
  5. */
  6. @Override
  7. public void backgroundProcess() {
  8. count = (count + 1) % processExpiresFrequency;
  9. if (count == 0) //如果达到检查频率则开始检查
  10. processExpires();
  11. }
  12.  
  13. /**
  14. * Invalidate all sessions that have expired.
  15. */
  16. public void processExpires() {
  17.  
  18. long timeNow = System.currentTimeMillis();
  19. Session sessions[] = findSessions(); //获取所有session对象
  20. int expireHere = 0 ; //过期session的数量,不要被这个变量名骗了
  21.  
  22. if(log.isDebugEnabled())
  23. log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length);
  24. for (int i = 0; i < sessions.length; i++) {
  25. if (sessions[i]!=null && !sessions[i].isValid()) {
  26. expireHere++;
  27. }
  28. }
  29. long timeEnd = System.currentTimeMillis();
  30. if(log.isDebugEnabled()) //打印记录
  31. log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere);
  32. processingTime += ( timeEnd - timeNow );
  33.  
  34. }

很多人看到这里,可能会有跟我一样的疑惑,即这里面根本就没有使Session过期失效的操作,好像只做了状态检查。不过后来看到了Session的isValid方法的实现就都明白了。

  1. /**
  2. * Return the <code>isValid</code> flag for this session.
  3. */
  4. @Override
  5. public boolean isValid() {
  6.  
  7. if (!this.isValid) {
  8. return false;
  9. }
  10.  
  11. if (this.expiring) {
  12. return true;
  13. }
  14.  
  15. if (ACTIVITY_CHECK && accessCount.get() > 0) {
  16. return true;
  17. }
  18.  
  19. //关键所在
  20. //如果有设置最大空闲时间
  21. //就获取此Session的空闲时间进行判断
  22. //如果已超时,则执行expire操作
  23. if (maxInactiveInterval > 0) {
  24. int timeIdle = (int) (getIdleTimeInternal() / 1000L);
  25. if (timeIdle >= maxInactiveInterval) {
  26. expire(true);
  27. }
  28. }
  29.  
  30. return this.isValid;
  31. }

 那这个空闲时间怎么得到?

其实就是记录上一次请求的时间,然后与本次请求的时间进行比对,得到时间差。

总结

总的来说,就是用一个线程来轮询会话状态,如果某个会话的空闲时间超过设定的最大值,则将该会话销毁。

【详解】Tomcat是如何监控并删除超时Session的?的更多相关文章

  1. 详解Tomcat 配置文件server.xml

    前言 Tomcat隶属于Apache基金会,是开源的轻量级Web应用服务器,使用非常广泛.server.xml是Tomcat中最重要的配置文件,server.xml的每一个元素都对应了Tomcat中的 ...

  2. 详解tomcat的连接数与线程池

    前言 在使用tomcat时,经常会遇到连接数.线程数之类的配置问题,要真正理解这些概念,必须先了解Tomcat的连接器(Connector). 在前面的文章 详解Tomcat配置文件server.xm ...

  3. 详解Tomcat的连接数和线程池

    转: https://www.cnblogs.com/kismetv/p/7806063.html#t11 前言 在使用tomcat时,经常会遇到连接数.线程数之类的配置问题,要真正理解这些概念,必须 ...

  4. 详解 Tomcat 的连接数与线程池

      前言 在使用tomcat时,经常会遇到连接数.线程数之类的配置问题,要真正理解这些概念,必须先了解Tomcat的连接器(Connector). 在前面的文章 详解Tomcat配置文件server. ...

  5. 详解tomcat连接数和线程数

    前言 在使用tomcat时,经常会遇到连接数.线程数之类的配置问题,要真正理解这些概念,必须先了解Tomcat的连接器(Connector). 在前面的文章 详解Tomcat配置文件server.xm ...

  6. 【转】详解tomcat的连接数与线程池

    对tomcat线程池.Connector的BIO.NIO解析的很透彻的一篇文章. 原文链接:https://www.cnblogs.com/kismetv/p/7806063.html 前言 在使用t ...

  7. 【tomcat系列】详解tomcat架构(上篇)

    java中,常用的web服务器一般由tomcat,weblogic,jetty,undertwo等,但从用户使用广泛度来说,tomcat用户量相对比较大一些,当然这也基于它开源和免费的特点. 从软件架 ...

  8. 详解Tomcat核心配置、http协议

    Tomcat服务器 Tomcat配置与部署(IDEA) https://www.cnblogs.com/gonghr/p/14731266.html Tomcat手工创建和打包第一个Web工程 在ap ...

  9. 详解 Spotlight on MySQL监控MySQL服务器

    前一章详解了Spotlight on Unix 监控Linux服务器 ,今天再来看看Spotlight on MySQL怎么监控MySQL服务器. 注:http://www.cnblogs.com/J ...

随机推荐

  1. 关于String类学习的一些笔记(本文参考来自程序员考拉的文章)

    String 类继承自 Object 超类,实现的接口有:Serializable.CharSequence.Comparable<String> 接口,具体如下图: 一.常用的Strin ...

  2. flume接收http请求,并将数据写到kafka

    flume接收http请求,并将数据写到kafka,spark消费kafka的数据.是数据采集的经典框架. 直接上flume的配置: source : http channel : file sink ...

  3. shiro简单配置 (写的不错 收藏一下)

    抄袭的连接:https://blog.csdn.net/clj198606061111/article/details/24185023 注:这里只介绍spring配置模式. 因为官方例子虽然中有更加 ...

  4. 可遇不可求的Question之SQLSERVER触发器不支持多行插入操作篇

    描述: 我们经常遇到 insert table_a select * from table_b 这样的语句, 同时在表table_a中根据每一条新增的SQL语句,通过触发器来触发对应的一系列的后续操作 ...

  5. 机器学习常用sklearn库

    Sklearn.model_selection(模型选择) Cross_val_score:交叉验证 Train_test_split:数据切割 GridsearchCV:网格搜索 Sklearn.m ...

  6. [转] KVM虚拟化技术生态环境介绍

    KVM虚拟化技术生态环境介绍 http://xanpeng.github.io/wiki/virt/kvm-virtulization-echosystem-intro.html kvm和qemu/q ...

  7. 使用bat脚本部署hexo到coding和github

    因项目的不同适当的改造吧,本文以hexo为例. 拉取coding.net的代码和github的代码到本地 确保代码能够正常的运行,commit,push 在项目的目录外新建一个push.bat文件 快 ...

  8. Android WebView 加载超长 JS 数据

    在之前的文章里面,我总结过WebView如何与网页交互,也就是Java如何和JS交互 —— Android WebView 总结 —— Java和JavaScript交互. 基于这篇文章,我们基本上能 ...

  9. Linux 下 安装Python第三方模块工具箱pip,以及用pip安装的方法

    下载文件 wget https://bootstrap.pypa.io/get-pip.py --no-check-certificate 执行安装 python get-pip.py 可以做一个软连 ...

  10. 【Spark调优】小表join大表数据倾斜解决方案

    [使用场景] 对RDD使用join类操作,或者是在Spark SQL中使用join语句时,而且join操作中的一个RDD或表的数据量比较小(例如几百MB或者1~2GB),比较适用此方案. [解决方案] ...