周六在公司加班,研究了下tomcat session失效的原理,直接上code,以后再补齐一些基本concept.
starttime = 2012-11-24 2:57pm (好久没update blog 看看写一篇用多久)
2种方式注销session
(1)主动 invoke Servlet API
/**
* Invalidates this session then unbinds any objects bound to it.
*
* @exception IllegalStateException
* if this method is called on an already invalidated session
*/
public void invalidate();
说明:这是HttpSession规范中定义的interface, 看note说将一个session注销然后解除其他对象的绑定. 也就是删除掉session object. 它要求throw 一个Exception
tomcat中实现是先 check session object 是不是valid的,如果invalid 直接throw IllegalStateException
然后开始处理,如下
/**
* Perform the internal processing required to invalidate this session,
* without triggering an exception if the session has already expired.
*
* @param notify Should we notify listeners about the demise of
* this session?
*/
public void expire(boolean notify) {
// Check to see if expire is in progress or has previously been called
if (expiring || !isValid)
return;
synchronized (this) {
// Check again, now we are inside the sync so this code only runs once
// Double check locking - expiring and isValid need to be volatile
if (expiring || !isValid)
return;
expiring = true;
setValid(false);
manager.remove(this, true);//在管理对象中讲这个session object删除(内部也是map实现的)
// 此处nofity标示是否在注销session的时候发送Evnet给listener,典型的观察者pattern
if (notify) {
fireSessionEvent(Session.SESSION_DESTROYED_EVENT, null);
}
expiring = false;
// Unbind any objects associated with this session
String keys[] = keys();
for (int i = 0; i < keys.length; i++)
removeAttributeInternal(keys[i], notify);
}
}
Note that:这段代码就是对specification的标准实现 我精简了一些,从code中学习到了一些知识
(1)如何扩展specification
(2)多线程争用,这个invalid其实是存在多线程mutex操作的。如果一个Thread_A将标志修改了,Thread_B一定要及时知道,所以对操作加以synchronized,对信号量如expiring variable采取volatile修饰保证内存可见性
(3)对于notification, 运用经典的观察者pattern
(4)其实tomcat的session实现还用到了外观等其他design pattern.(面试必背设计模式啊,哈哈)
(5)Map的组合应用(这个地球人都知道,我就不说了)
(2) timeout 注销
这个timeout最近深有体会,因为项目设计多线程并发,所以不确定因素很多,比如测试ftp connection等,也不能一直让它retrieve啊,哈哈,相信大家比我理解的深刻。
web app中大家都会配置timeout, 比如写在code中 或者xml中的session-timeout node里面,下面share下我学习的内部实现
容器类ContainerBase开始启动(tomcat定义了一套组件的lifecycle管理的,还没学习完),然后初始化init方法中开始做一些准备,最后会start一个thread来进行timeout check 的工作(this thread is a daemon thread)
具体的逻辑处理看code
/**
* Execute a periodic task, such as reloading, etc. This method will be
* invoked inside the classloading context of this container. Unexpected
* throwables will be caught and logged.
*/
@Override
public void backgroundProcess() {
if (!getState().isAvailable())
return;
if (cluster != null) {...}
if (loader != null) {...}
if (manager != null) {
manager.backgroundProcess();
}
//下面做一些pipe的信息处理和事件动作,不是重点就不说了
}
manager是session的管理对象,此处会调用它的处理逻辑,code如下
/**
* 此处比较有创意,是说这个Container被框架每调用6次,就会check一次session timeout 6次是默认的数值
*/
@Override
public void backgroundProcess() {
count = (count + 1) % processExpiresFrequency;
if (count == 0)
processExpires();
}
核心check timeout的逻辑就很简单了,上次access的时间和这次access的时间间隔是否大于我们定义的timeout.
学习到的东东:
(1)lifecycle
(2)线程执行方式
(3)模块化分类,code编码等等
nowtime=2012-11-24 3:28pm
cost = nowtime - starttime = 31min
用了30多分钟,失败,下篇一定要控制在30min-
有说的不对的地方请指教, 本文绝对原创,如需转载,注明出处(估计没人看)