最近有空看了一下tomcat 6源码里面对session管理的实现,现在写下来,以供后考,也希望能对对此感兴趣的朋友
有所提示。
闲话少说,先贴一下tomcat6的component层次图(此图来自tomcat doc)
Server 就是一个servlet container
|
Service 包含一个或多个connector的组
|
Engine servlet engine.最顶级的container.
| \
| --- Cluster --*
|
Host 第二级container
|
------
/ \
Cluster Context(1-N) 第三级container. servlet context. 也就是一个应用。
| \
| -- Manager 应用的session管理器
| \
| -- DeltaManager
| -- BackupManager
|
---------------------------
| \
Channel \
----------------------------- \
| \
Interceptor_1 .. \
| \
Interceptor_N \
----------------------------- \
| | | \
Receiver Sender Membership \
-- Valve
| \
| -- ReplicationValve
| -- JvmRouteBinderValve
|
-- LifecycleListener
|
-- ClusterListener
| \
| -- ClusterSessionListener
| -- JvmRouteSessionIDBinderListener
|
-- Deployer
\
-- FarmWarDeployer
OK,基本层级关系说过了,就开始分析session的管理。
1. session 的创建。
更正:下面这段我理解错了。其实进一步看下来,发现其实session的创建是在每个context里面。具体的创建可以看我
这篇之后的那篇文章. Session的生成实际是在调用最终处理的servlet的时候生成的。
session的创建的入口是在Host里面,每次request进来之后,会沿着container 的pipeline一直往下进行、
处理,顺序是:engine->host->context->wrapper. 而pipeline的作用就是调用对应级别的value对
request和response进行处理。在StandardHostValue里面首先出现对session的调用:
public final void invoke(Request request, Response response)
throws IOException, ServletException {
// Select the Context to be used for this Request
Context context = request.getContext();
if (context == null) {
response.sendError
(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
sm.getString("standardHost.noContext"));
return;
}
// Bind the context CL to the current thread
if( context.getLoader() != null ) {
// Not started - it should check for availability first
// This should eventually move to Engine, it's generic.
Thread.currentThread().setContextClassLoader
(context.getLoader().getClassLoader());
}
// Ask this Context to process this request
context.getPipeline().getFirst().invoke(request, response);
// Access a session (if present) to update last accessed time, based on a
// strict interpretation of the specification
if (Globals.STRICT_SERVLET_COMPLIANCE) {
request.getSession(false);
}
// Error page processing
response.setSuspended(false);
Throwable t = (Throwable) request.getAttribute(Globals.EXCEPTION_ATTR);
if (t != null) {
throwable(request, response, t);
} else {
status(request, response);
}
// Restore the context classloader
Thread.currentThread().setContextClassLoader
(StandardHostValve.class.getClassLoader());
}
注意里面的:request.getSession(false) 这一句。这一句最终会调用如下代码;
protected Session doGetSession(boolean create) {
// There cannot be a session if no context has been assigned yet
if (context == null)
return (null);
// Return the current session if it exists and is valid
if ((session != null) && !session.isValid())
session = null;
if (session != null)
return (session);
// Return the requested session if it exists and is valid
Manager manager = null;
if (context != null)
manager = context.getManager();
if (manager == null)
return (null); // Sessions are not supported
if (requestedSessionId != null) {
try {
session = manager.findSession(requestedSessionId);
} catch (IOException e) {
session = null;
}
if ((session != null) && !session.isValid())
session = null;
if (session != null) {
session.access();
return (session);
}
}
// Create a new session if requested and the response is not committed
if (!create)
return (null);
if ((context != null) && (response != null) &&
context.getCookies() &&
response.getResponse().isCommitted()) {
throw new IllegalStateException
(sm.getString("coyoteRequest.sessionCreateCommitted"));
}
// Attempt to reuse session id if one was submitted in a cookie
// Do not reuse the session id if it is from a URL, to prevent possible
// phishing attacks
if (connector.getEmptySessionPath()
&& isRequestedSessionIdFromCookie()) {
session = manager.createSession(getRequestedSessionId());
} else {
session = manager.createSession(null);
}
// Creating a new session cookie based on that session
if ((session != null) && (getContext() != null)
&& getContext().getCookies()) {
Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,
session.getIdInternal());
configureSessionCookie(cookie);
response.addCookieInternal(cookie, context.getUseHttpOnly());
}
if (session != null) {
session.access();
return (session);
} else {
return (null);
}
}
通过以上代码,container或者返回一个已存在的session,或者新建一个session,或者返回Null(特殊情况).
而session的创建是由manager完成的。Manager接口的实现根据具体情况有很多种,比如:
StandardManager:默认的单机环境tomcat session manager.创建standardsession.
DeltaSessionManager:适用于集群环境。创建DeltaSession
....
不同的Manager管理不同具体类型的session,从而使得tomcat能够很好的支持集群环境下面的session复制,持久化 等等。比如DeltaSession创建session的时候,会向集群中的其他节点群播一个信息。
2. session的管理。
大家都知道tomcat的session需要不断使超时的session失效,那么这个共是怎么实现的呢?
在StandardContext启动的时候哦,会同时启动一个thread. 这个线程是一个daemon线程,
会定时调用ManagerBase的一下方法:
public void processExpires() {
long 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]!=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具体实现的。比如DeltaSession:
public void expire(boolean notify, boolean notifyCluster) {
if (expiring)
return;
String expiredId = getIdInternal();
if(expiredId != null && manager != null &&
manager instanceof DeltaManager) {
DeltaManager dmanager = (DeltaManager)manager;
CatalinaCluster cluster = dmanager.getCluster();
ClusterMessage msg = dmanager.requestCompleted(expiredId, true);
if (msg != null) {
if(dmanager.doDomainReplication()) {
cluster.sendClusterDomain(msg);
} else {
cluster.send(msg);
}
}
}
super.expire(notify);
if (notifyCluster) {
if (log.isDebugEnabled())
log.debug(sm.getString("deltaSession.notifying",
((ClusterManager)manager).getName(),
new Boolean(isPrimarySession()),
expiredId));
if ( manager instanceof DeltaManager ) {
( (DeltaManager) manager).sessionExpired(expiredId);
}
}
}
可以看出,当session失效的时候,manager会广播这个消息。
分享到:
相关推荐
Tomcat_Session的持久化,详细讲解tomcatsession管理的原理和持久化原理
使用SpringSession管理多台tomcat的session同步到redis上
上文中在Tomcat的context.xml中配置了Session管理器RedisSessionManager,实现了通过redis来存储session的功能;Tomcat本身提供了多种Session管理器,如下类图: 1.Manager接口类 定义了用来管理session的基本...
主要介绍了深入浅析TomCat Session管理分析,需要的朋友可以参考下
tomcat-redis-session-tomcat tomcat无缝集成redis实现tomcat集群session管理,包含以下jar包:tomcat-redis-session-manager-VERSION.jar jedis-2.5.2.jar commons-pool2-2.2.jar
tomcat8专用session管理包,nginx+redis+tomcat8做负载均衡时要保持会话共享,需要用到的jar包
本资源已通过测试,资源包括所需jar包和配置说明,如果有不明白的可以在本人博客留言。
本资源通过Redisson组件实现Tomcat的非黏性会话管理功能,支持多个Tomcat共享存储Session会话信息,支持Tomcat的6.x、7.x、8.x版本,支持JDK1.8+或JDK1.6+环境。Redisson通过重定义Session相关类方法的方式实现...
Nginx 集群 tomcat session 共享配置有源码 介绍看博客:https://blog.csdn.net/wxb880114/article/details/80563301
memcached 实现session复制与同步需要的一整套jar
使用tomcat-redis-session-manager进行统一session管理所需jar包,包括tomcat6-jdk6、tomcat7-jdk7、tomcat8-jdk8
内置: 1、redis安装包 2、单机安装文档 3、集群安装文档 4、tomcat 单机session共享需要的文件和操作文档 5、tomcat 集群session共享需要的文件和操作文档
tomcat-redis-session-tomcat tomcat无缝集成redis实现tomcat集群session管理jar包
apache-tomcat-8.0.45以上版本 取消了LifecycleSupport ,而session管理器又不在维护,所有tomcat-8.0.45以上未能实现session同步
通过memcache实现tomcat7的session共享,目前生产环境用的不多了,但自己某个小需求用到,版本冲突好几次,分享给大家,这3个包复制到tomcat的 lib目录下 还有两个包需要 maven引入自己的项目中 <!-- memcache ...
使用tomcat-redis-session-manager进行统一session管理所需jar包,包括tomcat6-jdk6
利用redis存放tomcat7 session所需要的jar包。实际测试已通过,网上说使用common-pool2能够成功的都是瞎扯蛋
redis充当tomcat7 session store需要用到的jar包 使用说明: 1、将zip解压出来的jar包放到tomcat的lib目录下. 2、修改tomcat/conf下的context.xml文件,示例如下: <!-- Default set of monitored resources --> ...
Tomcat7集群扩展session集中管理,tomcat-redis-session-manager使用,所使用jar包和说明