javaweb之HttpSession对象

1.session会话追踪原理

客户端第一次请求服务端,服务端会创建一个session对象并且存储下来,之后会将session的唯一标识sessionId设置到响应头中传给客户端

客户端之后请求就会在cookie中携带第一次请求后服务端传过来的sessionId,服务端能通过客户端传过来的sessionId获取之前创建的session从而实现会话追踪

2.session的获取

session在服务端能通过request.getSession()获取

可以传参一个布尔值,request.getSession(true/false), true代表当根据sessionId未获取到session的时候会创建一个新的session,false当未获取到session时不会创建直接返回null。不传参这种情况默认true

/**
 * @return the session associated with this Request, creating one
 * if necessary.

 */
@Override
public HttpSession getSession() {
  Session session = doGetSession(true);
  if (session == null) {
    return null;
  }

  return session.getSession();
}

/**
 * @return the session associated with this Request, creating one
 * if necessary and requested.

 *
 * @param create Create a new session if one does not exist
 */
@Override
public HttpSession getSession(boolean create) {
  Session session = doGetSession(create);
  if (session == null) {
    return null;
  }

  return session.getSession();
}

3. 源码讲解

3.1 sessionId的获取

org.apache.catalina.connector.CoyoteAdapter#postParseRequest, 获取到后会将sessionId设置到request的requestedSessionId属性中,之后用字段表示这个sessionId是通过url、cookie、ssl哪一种方式获取的

3.2 session的创建

session的创建首先通过doGetSession方法再通过getSession方法获取,下面来详细分析

<span>org.apache.catalina.connector.Request#doGetSession</span>

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
  // &#x82E5;session&#x5931;&#x6548;&#xFF0C;&#x5219;&#x91CD;&#x7F6E;&#x4E3A;null
  if ((session != null) && !session.isValid()) {
    session = null;
  }
  if (session != null) {
    return session;
  }

  // Return the requested session if it exists and is valid
  // &#x83B7;&#x53D6;manager&#xFF0C;&#x6B64;&#x4E3A;&#x521B;&#x5EFA;session&#x7684;&#x7BA1;&#x7406;&#x5668;
  Manager manager = context.getManager();
  if (manager == null) {
    return null;      // Sessions are not supported
  }
  if (requestedSessionId != null) {
    try {
      // manager&#x4E2D;&#x7EF4;&#x62A4;&#x4E86;&#x4E00;&#x4E2A; protected Map<string, session> sessions = new ConcurrentHashMap<>(); &#x7F13;&#x5B58;
      // &#x5C1D;&#x8BD5;&#x6839;&#x636E;sessionId&#x4ECE;&#x7F13;&#x5B58;&#x4E2D;&#x83B7;&#x53D6;session
      session = manager.findSession(requestedSessionId);
    } catch (IOException e) {
      session = null;
    }
    // &#x662F;&#x5426;&#x9A8C;&#x8BC1;
    if ((session != null) && !session.isValid()) {
      session = null;
    }
    // &#x4E0D;&#x4E3A;&#x7A7A;&#x7684;&#x8BDD;&#x8BBF;&#x95EE;&#x6B21;&#x6570;&#x52A0;1&#xFF0C;&#x8FD4;&#x56DE;
    if (session != null) {
      session.access();
      return session;
    }
  }

  // Create a new session if requested and the response is not committed
  // &#x82E5;create=false&#xFF0C;&#x5219;&#x4E0D;&#x521B;&#x5EFA;&#x65B0;&#x7684;session&#x76F4;&#x63A5;&#x8FD4;&#x56DE;null
  if (!create) {
    return null;
  }
  boolean trackModesIncludesCookie =
      context.getServletContext().getEffectiveSessionTrackingModes().contains(SessionTrackingMode.COOKIE);
  // &#x54CD;&#x5E94;&#x5DF2;&#x63D0;&#x4EA4;&#x4E0D;&#x652F;&#x6301;&#x83B7;&#x53D6;session
  if (trackModesIncludesCookie && 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())  // &#x4E00;&#x822C;&#x4E0D;&#x8BBE;&#x7F6E;getSessionCookiePath&#x4E3A;null
      && 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 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;
      }
    }
  } else {
    // &#x903B;&#x8F91;&#x8FDB;&#x8FD9;&#x91CC;
    sessionId = null;
  }
  // &#x8C03;&#x7528;manager&#x521B;&#x5EFA;&#x4E00;&#x4E2A;&#x65B0;&#x7684;session&#xFF0C;&#x53C2;&#x6570;&#x4E3A;null
  session = manager.createSession(sessionId);

  // Creating a new session cookie based on that session
  if (session != null && trackModesIncludesCookie) {
    // &#x521B;&#x5EFA;&#x4E00;&#x4E2A;cookie &#x7C7B;&#x4F3C; JSESSIONID=AD726E115176BC2F4B1EF5F469F04603; Path=/zxq; HttpOnly
    Cookie cookie = ApplicationSessionCookieConfig.createSessionCookie(
        context, session.getIdInternal(), isSecure());
    // &#x6DFB;&#x52A0;&#x54CD;&#x5E94;&#xFF0C;header&#x4E3A;Set-Cookie
    response.addSessionCookieInternal(cookie);
  }

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

  // &#x8BBE;&#x7F6E;&#x8BBF;&#x95EE;&#x65F6;&#x95F4;&#x3001;&#x8BBF;&#x95EE;&#x6B21;&#x6570;&#x52A0;1
  session.access();
  return session;
}</string,>

org.apache.catalina.session.ManagerBase#createSession

@Override
public Session createSession(String sessionId) {

  // &#x5224;&#x65AD;&#x6D3B;&#x8DC3;session&#x6570;&#x636E;&#x662F;&#x5426;&#x5927;&#x4E8E;&#x6700;&#x5927;&#x503C;&#x3001;&#x5426;&#x5219;&#x62D2;&#x7EDD;&#x521B;&#x5EFA;session
  if ((maxActiveSessions >= 0) &&
      (getActiveSessions() >= maxActiveSessions)) {
    rejectedSessions++;
    throw new TooManyActiveSessionsException(
        sm.getString("managerBase.createSession.ise"),
        maxActiveSessions);
  }

  // Recycle or create a Session instance
  // &#x521B;&#x5EFA;&#x4E00;&#x4E2A;StandardSession&#x5B9E;&#x4F8B;
  Session session = createEmptySession();

  // Initialize the properties of the new session and return it
  session.setNew(true);
  session.setValid(true);
  session.setCreationTime(System.currentTimeMillis());
  // &#x8BBE;&#x7F6E;session&#x7684;&#x8FC7;&#x671F;&#x65F6;&#x95F4;
  session.setMaxInactiveInterval(getContext().getSessionTimeout() * 60);
  String id = sessionId;
  if (id == null) {
    // id&#x4E3A;&#x7A7A;&#x7684;&#x8BDD;&#x4F1A;&#x8C03;&#x7528;manager&#x7684;sessionIdGenerator&#x751F;&#x6210;&#x5668;&#x751F;&#x6210;&#x4E00;&#x4E2A;&#x65B0;&#x7684;sessionId
    id = generateSessionId();
  }
  // &#x8BBE;&#x7F6E;sessionId&#xFF0C;&#x540C;&#x65F6;&#x4F1A;&#x5C06;sessionId&#x548C;session&#x6DFB;&#x52A0;&#x5230;&#x4E0A;&#x9762;&#x63D0;&#x5230;&#x7684;&#x7F13;&#x5B58;&#x4E2D;&#x4F9B;&#x540E;&#x7EED;&#x83B7;&#x53D6;
  session.setId(id);
  // manager&#x7BA1;&#x7406;&#x7684;session&#x6570;&#x52A0;1
  sessionCounter++;

  SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);
  synchronized (sessionCreationTiming) {
    sessionCreationTiming.add(timing);
    sessionCreationTiming.poll();
  }
  return session;
}

发起一次请求响应如下,可以看到红框圈起来的就是服务端发送给客户端的sessionId,它是设置通过set-cookie设置在响应头中的,下一次请求客户端就会在cookie中带着该sessionId了

javaweb之HttpSession对象

Original: https://www.cnblogs.com/monianxd/p/16580976.html
Author: 默念x
Title: javaweb之HttpSession对象

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/620400/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球