Tomcat的Session管理(三)

摘要:PersistentManagerStandardManager的异同。

之前两篇关于session的文章主要讨论了session相关的创建、查询、过期处理。而我们查看源码的时候都是默认实现是StandardManager类,实际上实现也可以是PersistentManager类,下面我们就查看下该类的相关方法。

我们都知道PersistentManager代表的是持久化session的管理器。在PersistentManager类定义中有个变量org.apache.catalina.Store,该变量表示session管理器持久化session的方式,具体类图如下:

818454-20161205165908351-2096649172.jpg

Store

持久化存储方式的抽象类,定义了一些基本方法,例如save(),load(),keys(),clear()等。save()用来将session持久化到持久性介质中。load()方法从持久化介质中读取到内存中,keys()则返回所有的sessionId数组。clear()则清除所有的session。

StoreBase

抽象类,对Store作了基本实现。

FileStore

该类会将session对象存储到某个文件中,文件名会使用session对象的标识符再加上一个后缀.session构成。文件位于临时目录下,也可以调用FileStore类的setDirectroy()方法修改目录。

JDBCStore

该类将session对象通过jdbc存入数据库,因此使用该类需要使用jdbc链接。

鉴于save(),load()源码都很简单这里就不一一查看了。

我们继续讨论PersistentManager类相关方法。

RequestdoGetSession()方法中,我们之前默认manager实现类是StandardManager,如果tomcat中配置的是PersistentManager,那么manager.findSession(requestedSessionId)会略有不同,我们查看下源码(在PersistentManagerBase类中):

 @Override
public Session findSession(String id) throws IOException {//调用父类的findSession() 也就是ManagerBase类中的findSession,从现有内存中查找是否有指定的sessionSession session = super.findSession(id);// OK, at this point, we're not sure if another thread is trying to// remove the session or not so the only way around this is to lock it// (or attempt to) and then try to get it by this session id again. If// the other code ran swapOut, then we should get a null back during// this run, and if not, we lock it out so we can access the session// safely.//翻译下 英文注释// 代码运行到这里,因为我们不确定是否有别的线程要移除这个session,所以最保险的办法就是加锁再次尝试获取该session// 如果有其他代码正在执行 swapOut(将内存session持久化到介质中),那么我们应该返回null,如果没有的话,那么我们就可以安全的访问这个sessionif(session != null) {synchronized(session){session = super.findSession(session.getIdInternal());if(session != null){// To keep any external calling code from messing up the// concurrency.session.access();session.endAccess();}}}// 再次判断if (session != null)return session;// See if the Session is in the Store//从持久化介质中查找 session是否存在session = swapIn(id);return session;
}

查看 swapIn()方法:

 /*** Look for a session in the Store and, if found, restore* it in the Manager's list of active sessions if appropriate.* The session will be removed from the Store after swapping* in, but will not be added to the active session list if it* is invalid or past its expiration.** @return restored session, or {@code null}, if none is found*//*** 在Store(存储介质)中查找session,如果发现将把session恢复到该Manager的活跃session集合中。* 这个session将会从Store中移除,但是如果session过期或者无效将不会添加到活跃集合。*/protected Session swapIn(String id) throws IOException {if (store == null)return null;Object swapInLock = null;/** The purpose of this sync and these locks is to make sure that a* session is only loaded once. It doesn't matter if the lock is removed* and then another thread enters this method and tries to load the same* session. That thread will re-create a swapIn lock for that session,* quickly find that the session is already in sessions, use it and* carry on.*/synchronized (this) {swapInLock = sessionSwapInLocks.get(id);if (swapInLock == null) {swapInLock = new Object();sessionSwapInLocks.put(id, swapInLock);}}Session session = null;synchronized (swapInLock) {// First check to see if another thread has loaded the session into// the managersession = sessions.get(id);if (session == null) {try {if (SecurityUtil.isPackageProtectionEnabled()){try {session = AccessController.doPrivileged(new PrivilegedStoreLoad(id));} catch (PrivilegedActionException ex) {Exception e = ex.getException();log.error(sm.getString("persistentManager.swapInException", id),e);if (e instanceof IOException){throw (IOException)e;} else if (e instanceof ClassNotFoundException) {throw (ClassNotFoundException)e;}}} else {//加载session//1111111session = store.load(id);}} catch (ClassNotFoundException e) {String msg = sm.getString("persistentManager.deserializeError", id);log.error(msg, e);throw new IllegalStateException(msg, e);}if (session != null && !session.isValid()) {log.error(sm.getString("persistentManager.swapInInvalid", id));session.expire();removeSession(id);session = null;}if (session != null) {if(log.isDebugEnabled())log.debug(sm.getString("persistentManager.swapIn", id));session.setManager(this);// make sure the listeners know about it.((StandardSession)session).tellNew();add(session);((StandardSession)session).activate();// endAccess() to ensure timeouts happen correctly.// access() to keep access count correct or it will end up// negativesession.access();session.endAccess();}}}// Make sure the lock is removedsynchronized (this) {sessionSwapInLocks.remove(id);}return session;
}

可以看到主要的核心代码就是标注1的地方,Store.load(id),而这个源码配合Store.save(session)不管是FileStore还是JDBCStore都是很简单的,所以就不查看了。

除了getSession()方法有不同的地方,周期性任务的方法也略有不同。

ManagerBasebackgroundProcess()方法中:

    @Override
public void backgroundProcess() {count = (count + 1) % processExpiresFrequency;if (count == 0)processExpires();
}

因为processExpires()方法PersitentManagerBase中有复写的方法,所以会调用子类的方法。

   @Override
public void processExpires() {//111111111long timeNow = System.currentTimeMillis();Session sessions[] = findSessions();int expireHere = 0 ;if(log.isDebugEnabled())log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length);for (int i = 0; i < sessions.length; i++) {if (!sessions[i].isValid()) {expiredSessions.incrementAndGet();expireHere++;}}//222222processPersistenceChecks();if ((getStore() != null) && (getStore() instanceof StoreBase)) {((StoreBase) getStore()).processExpires();}long timeEnd = System.currentTimeMillis();if(log.isDebugEnabled())log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere);processingTime += (timeEnd - timeNow);}

在标注1到标注2之间的代码和之前查看的并无区别,基本就是将内存中的session一个个过期检查下。接着调用了processPersistenceChecks()方法。

 public void processPersistenceChecks() {//空闲时间超出一定的存储到存储器中processMaxIdleSwaps();//活跃session超出一定比例的存储到存储器中processMaxActiveSwaps();//空闲时间超出一定时间的进行备份processMaxIdleBackups();
}

因为三个方法都相差不大,就着了其中一个来查看下

 /*** Swap idle sessions out to Store if they are idle too long.*/
protected void processMaxIdleSwaps() {if (!getState().isAvailable() || maxIdleSwap < 0)return;//获取所有的sessionSession sessions[] = findSessions();long timeNow = System.currentTimeMillis();// Swap out all sessions idle longer than maxIdleSwap//一个变量,在server.xml里可以配置,session的最大空闲时间,超出session会被保存到存储器中,如果是负数,那么永远不保存if (maxIdleSwap >= 0) {for (int i = 0; i < sessions.length; i++) {StandardSession session = (StandardSession) sessions[i];synchronized (session) {if (!session.isValid())continue;int timeIdle;if (StandardSession.LAST_ACCESS_AT_START) {timeIdle = (int) ((timeNow - session.getLastAccessedTimeInternal()) / 1000L);} else {timeIdle = (int) ((timeNow - session.getThisAccessedTimeInternal()) / 1000L);}if (timeIdle >= maxIdleSwap && timeIdle >= minIdleSwap) {if (session.accessCount != null &&session.accessCount.get() > 0) {// Session is currently being accessed - skip itcontinue;}if (log.isDebugEnabled())log.debug(sm.getString("persistentManager.swapMaxIdle",session.getIdInternal(),Integer.valueOf(timeIdle)));try {//11111swapOut(session);} catch (IOException e) {// This is logged in writeSession()}}}}}}

查看标注1 的 swapOut(session)

protected void swapOut(Session session) throws IOException {if (store == null || !session.isValid()) {return;}((StandardSession)session).passivate();//222//写入到存储器中writeSession(session);//从活跃session名单中移除,也就是内存中移除super.remove(session, true);//回收session对象session.recycle();}

查看标注2的writeSession()

protected void writeSession(Session session) throws IOException {if (store == null || !session.isValid()) {return;}try {if (SecurityUtil.isPackageProtectionEnabled()){try{AccessController.doPrivileged(new PrivilegedStoreSave(session));}catch(PrivilegedActionException ex){Exception exception = ex.getException();if (exception instanceof IOException) {throw (IOException) exception;}log.error("Exception in the Store during writeSession: "+ exception, exception);}} else {//3333333store.save(session);}   } catch (IOException e) {log.error(sm.getString("persistentManager.serializeError", session.getIdInternal(), e));throw e;}}

可以看出最后还是调用的store.save(session)方法,就不再查看了,其他的processMaxActiveSwaps(),processMaxIdleBackups()方法都很类似,就留给读者自行查看了。

总的来说PersistentManagerStandardManager区别在于,PersistentManagerStandardManager的基础上额外增加了存储的功能,不管查找,删除,还是保存都需要在内存和存储器中同时进行。

总结:本文讨论了session管理器,该组件用来管理session管理中的session对象,解释了不同管理器的区别,以及session管理器如何把内存中session持久化到存储器中

最后附上相关配置:

web.xml中配置 session 的过期时间,默认30min

<session-config><session-timeout>30</session-timeout>
</session-config>

server.xml中配置 session管理器,默认StandardManager可以不配置,如果需要配置全局的session manager,可以在conf/context.xml中配置

StandardManager

当Tomcat服务器关闭或重启,或者Web应用被重新加载时,会对在内存中的HttpSession对象进行持久化, 并把它们保存到文件系统中,默认的文件为$CATALINA_HOME/work/Catalina/hostname/applicationname/SESSIONS.ser

<Context></Context>标签内配置<Manager></Manager>标签

<Manager className="org.apache.catalina.session.StandardManager" maxInactiveInterval="-1" />

备注:如果服务器异常关闭则所有会话都会丢失,StandardManager没有机会进行存盘处理

PersistentManager

<Manager className="org.apache.catalina.session.PersistentManager" saveOnRestart="true"maxActiveSessions="-1"minIdleSwap="60"maxIdleSwap="60"maxIdleBackup="60"><!--<Store  className="org.apache.catalina.session.FileStore" directory="../session" />--><Store className="org.apache.catalina.session.JDBCStore"driverName="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://url?user=user&amp;password=psd"sessionTable="tomcat_session" sessionIdCol="session_id" sessionDataCol="session_data" sessionValidCol="session_valid" sessionMaxInactiveCol="max_inactive" sessionLastAccessedCol="last_access"sessionAppCol="app_name" />
</Manager>
  • saveOnRestart:是否在重启的时候加载保存session
  • maxActiveSessions:最大允许session数量,-1 不限制
  • minIdleSwap:最小空闲时间,超出将会被转存到存储器中
  • maxIdleSwap:最大空闲时间,超出将会被转存到存储器中

Store相关:

  • directory:采用FileStore的时候指存储session的目录
  • sessionTable:存储session的表名
  • sessionIdCol:sessionid列名
  • sessionDataCol:sessionData列名
  • sessionValidCol:session是否有效列名
  • sessionMaxInactiveCol:session最大闲置时间列名
  • sessionLastAccessedCol:session上次访问时间列名
  • sessionAppCol:session归属的应用名称列名

(完)

转载于:https://www.cnblogs.com/coldridgeValley/p/6096143.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/456884.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

稳定和性能如何兼顾?58大数据平台的技术演进与实践

作者&#xff5c;赵健博 编辑&#xff5c;尚剑 本文将为你分享58大数据平台在最近一年半内技术演进的过程&#xff0c;包括&#xff1a;58大数据平台目前的整体架构是怎么样的&#xff1b;最近一年半的时间内我们面临的问题、挑战以及技术演进过程&#xff1b;以及未来的规划。…

Random Forest算法简介

转自JoinQuant量化课堂 一、相关概念 分类器&#xff1a;分类器就是给定一个样本的数据&#xff0c;判定这个样本属于哪个类别的算法。例如在股票涨跌预测中&#xff0c;我们认为前一天的交易量和收盘价对于第二天的涨跌是有影响的&#xff0c;那么分类器就是通过样本的交易量…

简单交互

控件有着各种事件&#xff0c;例如被点击的时候&#xff0c;我们可以在事件里面添加动作和命令&#xff0c;让控件可以和用户交互&#xff0c;这里我们演示一个简单的交互&#xff1a;当用户点击文字控件的时候&#xff0c;它开始动画向下移动然后动画旋转&#xff0c;效果入下…

综合素质计算机考点,教师资格证小学综合素质考点及考试真题:信息处理能力...

小学综合素质考点及考试真题——信息处理能力大纲要求&#xff1a;具有运用工具书检索信息、资料的能力。具有运用网络检索、交流信息的能力。具有对信息进行筛选、分类、存储和应用的能力。具有运用教育测量知识进行数据分析与处理的能力。具有根据教育教学的需要&#xff0c;…

API文档自动生成

本文主要讲述自动化API文档生成——apidoc。网上有几个篇文章都只是介绍apidoc的&#xff0c;具体怎么在自己的项目中使用以及与其他配合使用都是没介绍的。最近开始玩服务器&#xff0c;了解到了有Windows与Linux之间共享文件的方法&#xff0c;就是samba。然后具体和apidoc结…

机器学习笔记之SVM(SVR)算法

学过SVM后&#xff0c;看了那么多别人的文章&#xff0c;是时候自己总结一波了。权当写的笔记供自己日后再回顾吧。 PS:结合自己在工作过程中&#xff08;我这里用SVR做股票预测&#xff09;用到的知识来写的&#xff0c;不会很全面&#xff0c;若有些知识这里没提及读者可自行…

[转]基于图的机器学习技术:谷歌众多产品和服务背后的智能

近来机器学习领域实现了很多重大的进展&#xff0c;这些进展让计算机系统具备了解决复杂的真实世界问题的能力。其中&#xff0c;谷歌的机器学习又是怎样的 &#xff1f; 近来机器学习领域实现了很多重大的进展&#xff0c;这些进展让计算机系统具备了解决复杂的真实世界问题的…

安装mysql后在安装目录下只有my-default.ini没有my.ini文件 解决-The MySQL server is running with the --secure-file-priv

WIN10 系统环境 安装mysql后在安装目录下只有my-default.ini没有my.ini文件 。 mysql报错 ---------- The MySQL server is running with the --secure-file-priv option so it cannot execute this statement -------- 但是更改或想要查找配置文件就需要如下操作 在 安装…

loewe测试软件,实测Loewe三角包 最轻的小包最贴心的设计

原标题&#xff1a;实测Loewe三角包 最轻的小包最贴心的设计导语&#xff1a;每周一期的“包治百病”又跟大家见面来啦&#xff01;“包治百病”全方位评测包包的容量、重量、背法、在不同身高妹子身上的效果、各种惊人的小细节以及可能存在的问题&#xff0c;为有意购买这些包…

hadoop集群的搭建(分布式安装)

集群 计算机集群是一种计算机系统&#xff0c;他通过一组松散集成的计算机软件和硬件连接起来高度紧密地协同完成计算工作。集群系统中的单个计算机通常称为节点&#xff0c;通常通过局域网连接。集群技术的特点&#xff1a;1、通过多台计算机完成同一个工作。达到更高的效率 2…

解决:Error establishing a database connection阿里云修改数据库密码

今天闲来无事想把所有的二级密码改成一致的&#xff0c;所以就把阿里云的mysql数据库的密码改了&#xff0c;结果&#xff0c;打开页面报错了&#xff0c;下边的截图是我问题解决后&#xff0c;重新复现的。如果修复这个问题后wordpress登录页面白板&#xff0c;此时不要着急&a…

机器学习各算法思想(极简版)

读到的一篇不错的文章&#xff0c;拿来和大家分享一下。 转自–头条公众号–极数蜗牛 &#xff08;1&#xff09;线性回归 回归最早是由高尔顿研究子女身高与父母身高遗传关系提出的&#xff0c;发现子女平均身高总是向中心回归而得名。其实“一分辛苦一分才”中就蕴含了线性…

斯坦福计算机录取难吗,申请斯坦福究竟有多难? 什么样条件的人才能被斯坦福录取?斯坦福大学直播!...

原标题&#xff1a;申请斯坦福究竟有多难&#xff1f; 什么样条件的人才能被斯坦福录取&#xff1f;斯坦福大学直播&#xff01;申请斯坦福究竟有多难&#xff1f; 什么样条件的人才能被斯坦福录取&#xff1f;斯坦福大学直播&#xff01;西海岸小哈佛之称的斯坦福大学&#xf…

解决:building 'twisted.test.raiser' extension安装scrapy报错

解决&#xff1a;building twisted.test.raiser extension error: Microsoft Visual C 14.0 is required. Get it with "Microsoft Visual C Build Tools": https://visualstudio.microsoft.com/downloads/ 安装scrapy报错&#xff0c;在Twisted安装部分 解决方案…

Linux配置网络出现Eroor adding default gateway的解决方案

最近在学习有关大数据方面的东西&#xff0c;刚开始要搭建模拟的虚拟机集群。用的是Minimal CentOS6.7版本Linux下的系统。因为我要为各个虚拟机设置静态IP&#xff0c;所以就参考网上博客说的进行如下操作: 一、安装完系统后先配置网络&#xff1a; cd /etc/sysconfig/netwo…

揭秘8大自媒体平台注册方法,通过率百分之九十

写在前面&#xff1a;准备材料&#xff1a;手机号&#xff0c;邮箱&#xff0c;手持照&#xff0c;辅助材料(非必选项)&#xff0c;邀请码(非必选项)。辅助材料万能公式&#xff1a;方法①新浪博客16级博客发8篇相关的文章&#xff0c;昵称、描述、头像都与所注册自媒体号对应&…

计算机表格怎么求面积,在wps表格中怎么把数据生成面积图?

面积图强调数量随时间而变化的程度&#xff0c;适用于显示有限数量的若干组数据。可以利用面积图来分析销售的数据。在这里我用3种品牌的手提电脑在 2010年四个季度的销售量作为数据源&#xff0c;使用“堆积面积图”来显示各种手提电脑销售量所占大小并随时间变化的趋势。那么…

机器学习如何解决问题

原文 http://tech.meituan.com/mt-mlinaction-how-to-ml.html 前言 前言 随着大数据时代的到来&#xff0c;机器学习成为解决问题的一种重要且关键的工具。不管是工业界还是学术界&#xff0c;机器学习都是一个炙手可热的方向&#xff0c;但是学术界和工业界对机器学习的研究…

Linux中python2和python3的pip设置 及清华安装源

启动python2&#xff0c;我们可以直接在命令行输入&#xff1a;python2 启动python3&#xff0c;我们可以在命令行输入&#xff1a;python或者python3. 但是pip没有设置的话&#xff0c;在命令行输入 pip --version 或者 pip2 --version&#xff0c;指向的都是python2. 现在…

java 循环 基本类型

1.基本if选择结构 格式&#xff1a;if&#xff08;布尔表达式&#xff09;{ 表达式结果为true&#xff0c;则执行此代码块 } 例&#xff1a;if(week <5 ){ System.out.println(“上班”) } 2.if else结构 格式&#xff1a;if(布尔表达式){ 表达式结果为true&#xff0c;则执…