Tomcat中实现Session小结

2019-10-18 15:39:15丽君

那么,tomcat中多个会话对应的session是由谁来维护的呢?ManagerBase类,查看其代码,可以发现其有一个sessions成员属性,存储着各个会话的session信息:

  /**
   * The set of currently active Sessions for this Manager, keyed by
   * session identifier.
   */
  protected Map<String, Session> sessions = new ConcurrentHashMap<String, Session>();

接下来,看一下几个重要的方法,

服务器查找Session对象的方法

客户端每次的请求,tomcat都会在HashMap中查找对应的key为JSESSIONID的Session对象是否存在,可以查看Request的doGetSession方法源码,如下源码:

protected Session doGetSession(boolean create) {

    // There cannot be a session if no context has been assigned yet
    Context context = getContext();
    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 = 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.getServletContext().getEffectiveSessionTrackingModes().
          contains(SessionTrackingMode.COOKIE) &&
      response.getResponse().isCommitted()) {
      throw new IllegalStateException
       (sm.getString("coyoteRequest.sessionCreateCommitted"));
    }

    // Re-use session IDs provided by the client in very limited
    // circumstances.
    String sessionId = getRequestedSessionId();
    if (requestedSessionSSL) {
      // If the session ID has been obtained from the SSL handshake then
      // use it.
    } else if (("/".equals(context.getSessionCookiePath())
        && isRequestedSessionIdFromCookie())) {
      /* This is the common(ish) use case: using the same session ID with
       * multiple web applications on the same host. Typically this is
       * used by Portlet implementations. It only works if sessions are
       * tracked via cookies. The cookie must have a path of "/" else it
       * won't be provided to for requests to all web applications.
       *
       * Any session ID provided by the client should be for a session
       * that already exists somewhere on the host. Check if the context
       * is configured for this to be confirmed.
       */
      if (context.getValidateClientProvidedNewSessionId()) {
        boolean found = false;
        for (Container container : getHost().findChildren()) {
          Manager m = ((Context) container).getManager();
          if (m != null) {
            try {
              if (m.findSession(sessionId) != null) {
                found = true;
                break;
              }
            } catch (IOException e) {
              // Ignore. Problems with this manager will be
              // handled elsewhere.
            }
          }
        }
        if (!found) {
          sessionId = null;
        }
        sessionId = getRequestedSessionId();
      }
    } else {
      sessionId = null;
    }
    session = manager.createSession(sessionId);

    // Creating a new session cookie based on that session
    if ((session != null) && (getContext() != null)
        && getContext().getServletContext().
            getEffectiveSessionTrackingModes().contains(
                SessionTrackingMode.COOKIE)) {
      Cookie cookie =
        ApplicationSessionCookieConfig.createSessionCookie(
            context, session.getIdInternal(), isSecure());

      response.addSessionCookieInternal(cookie);
    }

    if (session == null) {
      return null;
    }

    session.access();
    return session;
  }