[转]Tomcat(6.0.14) Session创建机制简介

本文详细解析了Tomcat中Session的创建过程及过期策略,包括标准实现与非默认实现,帮助理解Session的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景:
公司的一个web应用,提交给测试部门做压力测试(由于不是我负责的,不清楚如何做的压力测试,以及测试指标),结果没压多久,就出现OutOfMemory.
接手协助原因查找,通过监控工具,发现StandardSession(org.apache.catalina.session.StandardSession)对象不断增长,毫无疑问,肯定是在不断创建Session对象.
备注:一般做压力测试,每次请求都不会指定JESSESIONID值,导致Web容器认为每次请求都是新的请求,于是创建Session对象.
同事负责代码Review,发现应用没有任何一个地方存放Session内容.困惑之...

问题:Tomcat容器何时创建Session对象?
想当然认为,只有动态存放Session内容的时候,才会创建Session对象.但是事实真得如此吗?

先看Servlet协议描述:
请看:
getSession(booleancreate)方法:

javax.servlet.http.HttpServletRequest.getSession(booleancreate)

ReturnsthecurrentHttpSessionassociatedwiththisrequestor,ififthereisnocurrentsessionandcreateistrue,returnsanewsession.

IfcreateisfalseandtherequesthasnovalidHttpSession,thismethodreturnsnull.

Tomakesurethesessionisproperlymaintained,youmustcallthismethodbeforetheresponseiscommitted.


简单地说:当create变量为true时,如果当前Session不存在,创建一个新的Session并且返回.

getSession()方法:

javax.servlet.http.HttpSessiongetSession();

Returnsthecurrentsessionassociatedwiththisrequest,oriftherequestdoesnothaveasession,createsone.

简单的说:当当前Session不存在,创建并且返回.


所以说,协议规定,在调用getSession方法的时候,就会创建Session对象.



既然协议这么定了,我们再来看看Tomcat是如何实现的:(下面的描述,是基于Tomcat6.0.14版本源码)
先看一张简单的类图:


ApplicationContext:Servlet规范中ServletContext的实现
StandardContext:Tomcat定义的Context默认实现.维护了一份SessionManager对象,管理Session对象.所有的Session对象都存放在Manager定义的Map<String,Session>容器中.
StanardManager:标准的Session管理,将Session存放在内容,Web容器关闭的时候,持久化到本地文件
PersistentManager:持久化实现的Session管理,默认有两种实现方式:
--持久化到本地文件
--持久化到数据库

了解了大概的概念后,回头再来看看org.apache.catalina.connector.Request.getSession()是如何实现的.
最终调用的是doGetSession(boolean create)方法,请看:

protectedSessiondoGetSession(booleancreate){

//Therecannotbeasessionifnocontexthasbeenassignedyet
if(context==null)
return(null);

//Returnthecurrentsessionifitexistsandisvalid
if((session!=null)&&!session.isValid())
session
=null;
if(session!=null)
return(session);

//Returntherequestedsessionifitexistsandisvalid
Managermanager=null;
if(context!=null)
manager
=context.getManager();
if(manager==null)
return(null);//Sessionsarenotsupported
if(requestedSessionId!=null){
try{
session
=manager.findSession(requestedSessionId);
}
catch(IOExceptione){
session
=null;
}
if((session!=null)&&!session.isValid())
session
=null;
if(session!=null){
session.access();
return(session);
}
}

//Createanewsessionifrequestedandtheresponseisnotcommitted
if(!create)
return(null);
if((context!=null)&&(response!=null)&&
context.getCookies()
&&
response.getResponse().isCommitted()){
thrownewIllegalStateException
(sm.getString(
"coyoteRequest.sessionCreateCommitted"));
}

//Attempttoreusesessionidifonewassubmittedinacookie
//DonotreusethesessionidifitisfromaURL,topreventpossible
//phishingattacks
if(connector.getEmptySessionPath()
&&isRequestedSessionIdFromCookie()){
session
=manager.createSession(getRequestedSessionId());
}
else{
session
=manager.createSession(null);
}

//Creatinganewsessioncookiebasedonthatsession
if((session!=null)&&(getContext()!=null)
&&getContext().getCookies()){
Cookiecookie
=newCookie(Globals.SESSION_COOKIE_NAME,
session.getIdInternal());
configureSessionCookie(cookie);
response.addCookieInternal(cookie,context.getUseHttpOnly());
}

if(session!=null){
session.access();
return(session);
}
else{
return(null);
}

}



至此,简单地描述了Tomcat Session创建的机制,有兴趣的同学要深入了解,不妨看看Tomcat源码实现.



补充说明,顺便提一下Session的过期策略.
过期方法在:
org.apache.catalina.session.ManagerBase(StandardManager基类) processExpires方法:

publicvoidprocessExpires(){

longtimeNow=System.currentTimeMillis();
Sessionsessions[]
=findSessions();
intexpireHere=0;

if(log.isDebugEnabled())
log.debug(
"Startexpiresessions"+getName()+"at"+timeNow+"sessioncount"+sessions.length);
for(inti=0;i<sessions.length;i++){
if(sessions[i]!=null&&!sessions[i].isValid()){
expireHere
++;
}
}
longtimeEnd=System.currentTimeMillis();
if(log.isDebugEnabled())
log.debug(
"Endexpiresessions"+getName()+"processingTime"+(timeEnd-timeNow)+"expiredsessions:"+expireHere);
processingTime
+=(timeEnd-timeNow);

}


其中,Session.isValid()方法会做Session的清除工作.


在org.apache.catalina.core.ContainerBase中,会启动一个后台线程,跑一些后台任务,Session过期任务是其中之一:

protectedvoidthreadStart(){

if(thread!=null)
return;
if(backgroundProcessorDelay<=0)
return;

threadDone
=false;
StringthreadName
="ContainerBackgroundProcessor["+toString()+"]";
thread
=newThread(newContainerBackgroundProcessor(),threadName);
thread.setDaemon(
true);
thread.start();

}

准确地讲,除非你的应用完全不需要保存状态(无状态应用),不然地话,只要有一个新的连接过来,web容器都需要创建Session概念,维护状态信息.
但是Session是什么?Session仅仅是一个概念:"Provides a way to identify a user across more than one page request or visit to a Web site and to store information about that user."--简单地讲,保存用户状态信息.
所以说,我们完全可以根据应用的需求,定制Session的实现:
a. Session保存到JVM内容中--Tomcat默认的实现
b. Session保存到Cookie中--Cookie-Based Session
c. Session保存到本地文件--Tomcat提供的非默认实现之一
d. Session保存到Cache Store中--比如常见的Memcached
e. Session保存到数据库中--比如保存到mysql数据库session表,中间对于活跃的Session 缓存到cached中.
......
那么,假如一个应用有大量一次性不同用户的请求(仅仅是一次性的,比如上述文章描述的场景),那么选择c,d,e方案都能有效解决文中所描述的问题.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值