前段时间看了阵子Tomcat的源码,有所得。早想总结出来可惜太多了,不知道从何说起,今天早上有时间先从Session如何实现的说起吧,免得时间越久忘记的越多。
Tomcat的容器有四个级别,分别为Engine、Host、Context和Wrapper。所有的容器都有相同的父类,即org.apache.catalina.core.ContainerBase。那么session的管理在哪个级别的,Engine、Host还是Context?答案是在Context级别实现的,即每个应用有自己的session管理对象。
StandardContext是Context容器(即你的应用)的标准实现,在其start方法中(即启动时候)将创建该应用的session管理对象,非集群的情况下Session管理对象类为org.apache.catalina.session.StandardManager,它是session的标准管理器,每个Context(应用)关联一个,它实现了session的创建、查询、过期检测和序列化和反序列化,序列化和反序列化是在容器重启过程中用到的,保证重启不会丢失活动的session。
StandardContext的父类是org.apache.catalina.session.ManagerBase,其session的保存变量声明为protected Map<String, Session> sessions = new ConcurrentHashMap<String, Session>();即利用ConcurrentHashMap保存session,如果想所有的应用共用一个session可以先将此变量设置为static的,然后修改设置cookie的JSESSION的path为“/”。
Session的创建——当request.getSession时候,根据请求中cookie中的或者url后的JSESSION参数查找session,如果存在则返回相应的session,不存在则创建并在响应(response)设置头信息,要求设置客户端cookie的JSESSION为session的id,path为应用的路径。
Session的过期检测——session的超时检测如何实现的呢?
在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);
}
}
}
protected void processChildren(Container container, ClassLoader cl) {
try {
if (container.getLoader() != null) {
Thread.currentThread().setContextClassLoader
(container.getLoader().getClassLoader());
}
container.backgroundProcess();
} catch (Throwable t) {
log.error("Exception invoking periodic operation: ", t);
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
Container[] children = container.findChildren();
for (int i = 0; i < children.length; i++) {
if (children[i].getBackgroundProcessorDelay() <= 0) {
processChildren(children[i], cl);
}
}
}
}
当容器启动中会创建此类并运行,该类为多线程实现,即相当于启动一个与该容器相关的后台运行的线程。这个run方法中递归调用容器的processChildren方法,该方法首先运行容器相关的backgroundProcess方法,然后再递归调用子容器的processChildren,在backgroundProcess方法中会启动可能与容器相关的各种后台程序。其代码如下:
public void backgroundProcess() {
if (!started)
return;
if (cluster != null) {
try {
cluster.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString("containerBase.backgroundProcess.cluster", cluster), e);
}
}
if (loader != null) {
try {
loader.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString("containerBase.backgroundProcess.loader", loader), e);
}
}
if (manager != null) {
try {
manager.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString("containerBase.backgroundProcess.manager", manager), e);
}
}
if (realm != null) {
try {
realm.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString("containerBase.backgroundProcess.realm", realm), e);
}
}
Valve current = pipeline.getFirst();
while (current != null) {
try {
current.backgroundProcess();
} catch (Exception e) {
log.warn(sm.getString("containerBase.backgroundProcess.valve", current), e);
}
current = current.getNext();
}
lifecycle.fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);
}
其中如果为Context容器则会启动manager,此manager即为StandardManager,在其父类ManagerBase中的backgroundProcess方法如下:
/**
* Implements the Manager interface, direct call to processExpires
*/
public void backgroundProcess() {
count = (count + 1) % processExpiresFrequency;
if (count == 0)
processExpires();
}
processExpiresFrequency默认为6,相当于每过6秒检测一次,检测方法主要调用session的isValid方法,该方法判断当前时间与最近访问时间间隔是否超过设定的时间间隔。
另外,每次访问应用,都会调用StandardSession的access方法,即更新最近访问时间。
要工作了,最后还有session的监听的实现, 注册监听是在应用的web.xml中声明的,那么相应的监听也是保存在Context容器的变量中,其getApplicationLifecycleListeners()方法获得容器的监听数组,其声明为:
private transient Object applicationLifecycleListenersObjects[] =
new Object[0];
在StandardSession的expire方法如下:
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) {
// Ignore
}
manager.getContainer().getLogger().error
(sm.getString("standardSession.sessionEvent"), t);
}
}
}
如果监听为对Session的监听,则触发监听,而在创建session的设置session的id方法中会调用tellNew(),其会触发session创建时session监听程序。
就这么多吧,要上班了。。。
分享到:
相关推荐
Apache Tomcat源码分析 Apache Tomcat是一款广泛应用的开源Java Servlet容器,它是Java EE Web应用程序的标准实现。Tomcat源码的深入理解对于Java Web开发者来说是至关重要的,它可以帮助我们了解HTTP服务器的工作...
【标题】:“Tomcat Redis Session”指的是在Tomcat集群环境中,通过Redis来实现Session的共享与同步,以解决集群中的Session一致性问题。 【描述】:“Tomcat集群Nginx使用Redis保证Session同步”这一场景中,通常...
本文将深度剖析`Tomcat-Redis-Session-Manager`的源码,揭示其如何实现Tomcat与Redis之间的会话同步。 首先,我们来看`Tomcat-Redis-Session-Manager`的核心功能:它将Tomcat默认的内存会话管理替换为基于Redis的...
下面我们将详细探讨如何实现Nginx+Tomcat+Memcached的集群和Session共享。 **Nginx** Nginx是一款轻量级的Web服务器/反向代理服务器,以其高效的性能和低内存占用著称。在本场景中,Nginx主要负责以下任务: 1. **...
本篇文章将探讨如何利用Redis、Tomcat和Nginx来实现Session共享,以便在分布式环境中保持用户状态的一致性。 首先,让我们了解一下Session的概念。Session是Web服务器用来跟踪用户状态的一种机制。当用户登录后,...
这个组件实现了将Tomcat应用服务器中的用户session数据存储到Redis分布式缓存系统中,以提高系统的可伸缩性和性能。Redis是一个高性能的键值数据库,常被用来作为缓存服务,因其速度快、数据持久化等特点,非常适合...
2. **准备Jar包**: 压缩包文件"tomcat8-redis-session-manager"包含实现Tomcat8与Redis交互所需的库,如`jedis.jar`(用于Java操作Redis)和可能的session管理器实现,如`tomcat-redis-session-manager.jar`。...
此外,源码中还有许多值得关注的部分,如会话管理(SessionManager)、监听器(Listener)的注册、错误处理(ErrorReportValve)、部署工具(Deployer)等。理解这些组件的工作原理,将有助于我们在实际开发中遇到...
本文将详细讲解如何通过Redis实现Tomcat7的session共享,并介绍相关配置和依赖包。首先,我们来看一下核心的组件:Redis、Tomcat7以及session管理。 Redis是一个开源的、基于内存的数据结构存储系统,它可以作为...
Apache Tomcat 8.5.23 源码分析 Apache Tomcat 是一个开源的、免费的Web服务器和Servlet容器,它实现了Java Servlet和JavaServer Pages(JSP)规范,...因此,对Tomcat源码的学习对于Java Web开发者来说是至关重要的。
源码可以帮助我们深入了解Session共享的具体实现,包括如何序列化和反序列化Session对象,如何处理并发访问,以及如何在Redis中设置和获取Session数据等。通过阅读源码,开发者可以学习到如何自定义Session管理器,...
这些jar包通常包括Tomcat的Redis Session Manager实现以及Redis客户端库(如Jedis)。将这些jar包添加到Tomcat的`lib`目录下,使得Tomcat在启动时能够加载它们。 4. **配置Redis Session Manager**:除了在`server....
本文将围绕“tomcat-redis-session-manager-master.zip”这个压缩包中的源码,深入探讨如何使用Redis实现Tomcat的session共享,并提供详尽的知识点解析。 首先,我们要理解Tomcat的session管理基础。在默认情况下,...
标题中的"redis+tomcat实现session的jar"指的是在Tomcat服务器中利用Redis数据库来实现Web应用程序的会话(session)共享技术。Redis是一个高性能的键值存储系统,常用于缓存和分布式环境下的数据共享。在传统的Web...
【标题】"resis实现tomcat7 session 共享"主要涉及的是在分布式环境中如何实现Tomcat服务器间的Session共享问题。Resin(ReStructured Servlet & JSP Engine)是一款轻量级、高性能的Java应用服务器,它支持Servlet...
《深入理解Tomcat源码与Servlet-API》 Tomcat,作为Apache软件基金会的顶级项目,是Java Servlet和JavaServer Pages(JSP)的开源Web应用服务器,被广泛应用于中小型企业的Web服务部署。7.0.59版本是Tomcat的一个...
很好用,使用也很简单,把其中的三个Jar包拷贝到你的tomcat中的...tomcat8、8.5、9与redis实现session共享,并可以通过修改源码可自定义session键,访问地址:http://blog.csdn.net/fackyou200/article/details/78929008
这个包里含有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的共享。 首先,我们需要了解什么是Session。在Web开发中,Session是用于跟踪用户状态的一种技术。当用户登录后,服务器会为每个用户创建一个唯一的Session ID,...
通过这种方式,Tomcat 8和Redis结合,能够实现高效的Session共享,确保用户在分布式环境中的会话一致性。注意,使用Redis存储Session时,需要注意数据的持久化策略以及Redis的内存管理,避免内存溢出。同时,考虑到...