下面谈一谈Session的管理。
一. Session的管理
当tomcat启动时,会开启一个后台线程,这个后台线程是随容器的启动而启动的,它将定期检查会话超时。
(org.apache.catalina.core.ContainerBase.threadStart())
protected void threadStart() {
if (thread != null)
return;
//
if (backgroundProcessorDelay <= 0)
return;
threadDone = false;
String threadName = "ContainerBackgroundProcessor[" + toString() + "]";
thread = new Thread(new ContainerBackgroundProcessor(), threadName);
thread.setDaemon(true);
thread.start();
}
1.此时会新建一个ContainerBackgroundProcessor线程。
(org.apache.catalina.core.ContainerBase.ContainerBackgroundProcessor)
protected class ContainerBackgroundProcessor implements Runnable {
public void run() {
while (!threadDone) {
try {
Thread.sleep(backgroundProcessorDelay * 1000L);
} catch (InterruptedException e) {
;
}
if (!threadDone) {
Container parent = (Container) getMappingObject();
ClassLoader cl =
Thread.currentThread().getContextClassLoader();
if (parent.getLoader() != null) {
cl = parent.getLoader().getClassLoader();
}
processChildren(parent, cl);//parent为StandardEngine
}
}
}
2.processChildren(parent,cl)--->processChildren(StandardHost,cl) --->processChildren(StandardContext,cl),最后StandardContext#backgroundProcess()方法被调用。
(org.apache.catalina.core.StandardContext.backgroundProcess())
public void backgroundProcess() {
if (!started)
return;
count = (count + 1) % managerChecksFrequency;
if ((getManager() != null) && (count == 0)) {
try {
getManager().backgroundProcess();
} catch ( Exception x ) {
log.warn("Unable to perform background process on manager",x);
}
}
3. StandardManager#processExpires()方法被调用。
org.apache.catalina.session.StandardManager.backgroundProcess()
public void backgroundProcess() {
processExpires();
}
4. StandardManager#processExpires()被调用,通过调用session#isValid()方法判断session是否有效,如果session无效将被销毁。
(org.apache.catalina.session.StandardManager.processExpires())
/**
* 处理所有已失效的session
*/
public void processExpires() {
long timeNow = System.currentTimeMillis();
Session sessions[] = findSessions();
for (int i = 0; i < sessions.length; i++) {
StandardSession session = (StandardSession) sessions[i];
if (!session.isValid()) {
expiredSessions++;
}
}
long timeEnd = System.currentTimeMillis();
processingTime += ( timeEnd - timeNow );
}
5.StandardSession#isValid()最终调用expire(true),然后返回isValid()的布尔值。
(org.apache.catalina.session.StandardSession.isValid())
public boolean isValid() {
if (this.expiring) {
return true;
}
if (!this.isValid ) {
return false;
}
if (accessCount > 0) {
return true;
}
if (maxInactiveInterval >= 0) {
long timeNow = System.currentTimeMillis();
int timeIdle = (int) ((timeNow - thisAccessedTime) / 1000L);
if (timeIdle >= maxInactiveInterval) {
expire(true);※3
}
}
return (this.isValid);
}
※3
StandardSession.expire()方法被调用,session被销毁。
(org.apache.catalina.session.StandardSession.expire(boolean notify))
public void expire(boolean notify) {
if (expiring)
return;
synchronized (this) {
if (manager == null)
return;
expiring = true;
//唤醒相关的应用程序事件监听者
Context context = (Context) manager.getContainer();
Object listeners[] = context.getApplicationLifecycleListeners();
if (notify && (listeners != null)) {
HttpSessionEvent event =
new HttpSessionEvent(getSession());
for (int i = 0; i < listeners.length; i++) {
int j = (listeners.length - 1) - i;
if (!(listeners[j] instanceof HttpSessionListener))
continue;
HttpSessionListener listener =
(HttpSessionListener) listeners[j];
try {
fireContainerEvent(context,
"beforeSessionDestroyed",
listener);
listener.sessionDestroyed(event);
fireContainerEvent(context,
"afterSessionDestroyed",
listener);
} catch (Throwable t) {
try {
fireContainerEvent(context,
"afterSessionDestroyed",
listener);
} catch (Exception e) {
;
}
manager.getContainer().getLogger().error
(sm.getString("standardSession.sessionEvent"), t);
}
}
}
accessCount = 0;
setValid(false);
// Remove this session from our manager's active sessions
if (manager != null)
manager.remove(this);
//唤醒相关的session事件监听者
if (notify) {
fireSessionEvent(Session.SESSION_DESTROYED_EVENT, null);
}
// 处理完毕后,设置expiring为false
expiring = false;
//解除任何与此相关的session对象的绑定
String keys[] = keys();
for (int i = 0; i < keys.length; i++)
removeAttributeInternal(keys[i], notify);
}
}
分享到:
相关推荐
tomcat-redis-session-manager源码
Tomcat8亲测可用 tomcat-redis-session-manager的jar包 修改了tomcat-redis-session-manager源码进行的编译生成的jar包
这个包里含有commons-pool2-2.4.2、jedis-2.9.0、tomcat85-session-redis-1.0三个主要JAR包。apache-tomcat-8.5.20.tar.gz源码包和context.xml文件,这套配置是我自己亲测可用的。。另外我用的redis4这个版本。注意...
基于tomcat-redis-session-manager源码进行的编译生成的jar包,压缩包中包含Tomcat7和Tomcat8打好的jar包。
因tomcat7使用redis共享session,其他的包存在问题,自己编译后处理通过。 该包是在https://github.com/jcoleman/tomcat-redis-session-manager 将源码编译后的包。
自己通过源码编译后的jar包,已实验可以正常使用
tomcat8下 tomcat-redis-session-manager , github上有源码,其他版本都有打好的jar包,tomcat 8 下没有,下载源码生成了一个。
tomcat-redis-session-manager-master,修改了github上的源码,有三个版本,支持tomcat8.0,tomcat8.5和tomcat9
tomcat session共享源码学习
tomcat 集群 nginx 使用redis 保证session同步
Tomcat集群Redis会话管理器 Redis会话管理器是可插入的。 它将会话存储到Redis中,以便在Tomcat服务器群集之间轻松分配HTTP请求。 在这里,会话被实现为非粘性的(意味着,每个请求都可以转到集群中的任何服务器,...
基于tomcat-redis-session-manager源码进行的编译生成的jar包,压缩包中包含Tomcat7和Tomcat8打好的jar包。
基于tomcat-redis-session-manager源码进行的编译生成的jar包,压缩包中包含Tomcat7和Tomcat8打好的jar包。
压缩包里是我自己下载源码测试打包的memcached-session-manager-1.9.3 for tomcat6相关jar文件,序列化采用的是kryo-serializer。我的运行环境是:JDK1.6+TOMCAT6.0.45,MSM加Tomcat有一个特别大的坑是如果Tomcat版本是...
包含源码和源码编译后的包。
用户环境必须使用tomcat6,且想做集群环境,没办法只得找资源,可惜网上tomcat6的资源比较少,而且本人找到的基本都有错误,不能保存session进redis,导致每次测试页面都生成新的sessionid,所以最后自己跟源码解决...
tomcat8、8.5、9与redis实现session共享,并可以通过修改源码可自定义session键,访问地址:http://blog.csdn.net/fackyou200/article/details/78929008
解决race condition问题,根据git最新源码编译
解压该文件,将里面的jar包丢Tomcat7目录lib下进行相关配置即可(配置网上有),由官方git地址:https://github.com/jcoleman/tomcat-redis-session-manager 源码进行打包 jar 加入依赖包 后生产的jar 直接放入...