前言
偶然发现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关闭时(注意是正常的关闭操作,而非突然崩溃),会把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
3
4
5
|
/** * the set of currently active sessions for this manager, keyed by * session identifier. */ protected map<string, session> sessions = new concurrenthashmap<>(); |
当一个请求到达context的时候,如果它带有jsessionid的cookie,manager就能依此找到关联的session对象,放入到request对象中。
manager的定期检查
manager接口有一个backgroundprocess()方法,顾名思义就是后台处理。
1
2
3
4
5
6
|
/** * this method will be invoked by the context /container on a periodic * basis and allows the manager to implement * a method that executes periodic tasks, such as expiring sessions etc. */ public void backgroundprocess(); |
注:container接口也有这个方法,这个方法一般在容器启动(start)的时候,开启一个额外的线程来执行这个backgroundprocess方法。其中context的这个方法启动后,会执行loader和manager的backgroundprocess方法。
我们来看看这个方法都做了些什么?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
/** * {@inheritdoc} * <p> * direct call to {@link #processexpires()} */ @override public void backgroundprocess() { count = (count + 1) % processexpiresfrequency; if (count == 0) // 如果达到检查频率则开始检查 processexpires(); } /** * invalidate all sessions that have expired. */ public void processexpires() { long timenow = system.currenttimemillis(); session sessions[] = findsessions(); // 获取所有session对象 int expirehere = 0 ; // 过期session的数量,不要被这个变量名骗了 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]!=null && !sessions[i].isvalid()) { expirehere++; } } long timeend = system.currenttimemillis(); if (log.isdebugenabled()) // 打印记录 log.debug( "end expire sessions " + getname() + " processingtime " + (timeend - timenow) + " expired sessions: " + expirehere); processingtime += ( timeend - timenow ); } |
很多人看到这里,可能会有跟我一样的疑惑,即这里面根本就没有使session过期失效的操作,好像只做了状态检查。不过后来看到了session的isvalid方法的实现就都明白了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
/** * return the <code>isvalid< /code > flag for this session. */ @override public boolean isvalid() { if (!this.isvalid) { return false ; } if (this.expiring) { return true ; } if (activity_check && accesscount.get() > 0) { return true ; } // 关键所在 // 如果有设置最大空闲时间 // 就获取此session的空闲时间进行判断 // 如果已超时,则执行expire操作 if (maxinactiveinterval > 0) { int timeidle = (int) (getidletimeinternal() / 1000l); if (timeidle >= maxinactiveinterval) { expire( true ); } } return this.isvalid; } |
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对服务器之家的支持。
原文链接:http://www.cnblogs.com/longfurcat/p/10705862.html