首页 > 学院 > 开发设计 > 正文

tomcat session管理

2019-11-08 02:10:33
字体:
来源:转载
供稿:网友

最近有空看了一下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的调用:

 

java代码  收藏代码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) 这一句。这一句最终会调用如下代码;

  

Java代码  收藏代码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的一下方法:

  

Java代码  收藏代码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:

  

Java代码  收藏代码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会广播这个消息。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表