Tomcat6 Session建立机制简要

底:
  测试部门做压力测试, 结果没多久新闻,出现OutOfMemory.
 查找原因,通过监视工具,查找StandardSession(org.apache.catalina.session.StandardSession)对象不断增长,毫无疑问,肯定是在不断创建Session对象.
备注:一般做压力測试,每次请求都不会指定JESSESIONID值,导致Web容器觉得每次请求都是新的请求,于是创建Session对象.
同事负责代码Review,发现应用没有不论什么一个地方存放Session内容.困惑之...

问题:Tomcat容器何时创建Session对象?


想当然觉得,唯独动态存放Session内容的时候,才会创建Session对象.可是事实真得如此吗?

先看Servlet协议描写叙述:
请看:
getSession(boolean create)方法:

javax.servlet.http.HttpServletRequest.getSession(boolean create)

Returns the current HttpSession associated with this request or, if if there is no current session and create is true, returns a new session. 

If create is false and the request has no valid HttpSession, this method returns null. 

To make sure the session is properly maintained, you must call this method before the response is committed.

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

getSession()方法:
javax.servlet.http.HttpSession getSession();

Returns the current session associated with this request, or if the request does not have a session, creates one.
简单的说:当当前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)方法,请看:
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);
        }

    }


至此,简单地描写叙述了Tomcat Session创建的机制,有兴趣的同学要深入了解,最好还是看看Tomcat源代码实现.



补充说明,顺便提一下Session的过期策略.
过期方法在:
org.apache.catalina.session.ManagerBase(StandardManager基类) processExpires方法:
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.isValid()方法会做Session的清除工作.


在org.apache.catalina.core.ContainerBase中,会启动一个后台线程,跑一些后台任务,Session过期任务是当中之中的一个:
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();

    }

准确地讲,除非你的应用全然不须要保存状态(无状态应用),不然地话,只要有一个新的连接过来,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程序可以是本文所述的有效的解决方案描述的问题.

版权声明:本文博主原创文章。博客,未经同意不得转载。

原文地址:https://www.cnblogs.com/blfshiye/p/4905409.html