Session is an object that records the server session. It can track a series of actions of the user from logging in to closing the browser. The specific creation code
public void addSession(HttpServletRequest request,String key,String value){ HttpSession session = request.getSession(); session.setAttribute(key, value); }
Obtain the session object through the HttpServletRequest object, corresponding to the getSession() method of org.apache.catalina.connector.RequestFacade under tomcat
@Override public HttpSession getSession() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return getSession(true); }
Call the getSession(create) method
@Override //create parameter is whether to create a session. If false, there is no corresponding session in the server, then return null public HttpSession getSession(boolean create) { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } if (SecurityUtil.isPackageProtectionEnabled()){ return AccessController. doPrivileged(new GetSessionPrivilegedAction(create)); } else { return request.getSession(create); } }
Transfer the acquired session to the org.apache.catalina.connector.Request class for processing. RequestFacade is a facade class of the Request class. It wraps the method call of the Request and is open to the outside world, hiding the implementation details of the Request.
The getSession(create) method of the Request class is called
@Override public HttpSession getSession(boolean create) { / / Process to get the session Session session = doGetSession(create); if (session == null) { return null; } return session.getSession(); }
Session session = doGetSession(create); This session is the session interface of tomcat, not under java.javax.
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 the jsessionId in the cookie, or the URL paramaters is not empty, // Find the session through the manager manager
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")); } // 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 // Use the SSL session ID if one is present. if (("/".equals(context.getSessionCookiePath()) && isRequestedSessionIdFromCookie()) || requestedSessionSSL) { session = manager.createSession(getRequestedSessionId()); } else { session = manager.createSession(null); } // 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; }
The requestedSessionId is parsed by the postParseRequest method under org.apache.catalina.connector.CoyoteAdapter. The specific code snippet
// Now we have the context, we can parse the session ID from the URL // (if any). Need to do this before we redirect in case we need to // include the session id in the redirect String sessionID = null; if (request.getServletContext().getEffectiveSessionTrackingModes() .contains(SessionTrackingMode.URL)) { // Get the session ID if there was one sessionID = request.getPathParameter( SessionConfig.getSessionUriParamName( request.getContext())); if (sessionID != null) { request.setRequestedSessionId(sessionID); request.setRequestedSessionURL(true); } } // Look for session ID in cookies and SSL session parseSessionCookiesId(req, request); parseSessionSslId(request); sessionID = request.getRequestedSessionId();
The management of the session is the Manager interface, under the org.apache.catalina package. Specifically, the implementation class is ManagerBase
//If the jsessionId in the cookie, or the URL paramaters is not empty, find the session through the manager manager 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); } }
Corresponding to the ManagerBase class
@Override public Session findSession(String id) throws IOException { if (id == null) return (null); return sessions.get(id); }
sessions is a property of the ManagerBase object,
protected Map<String, Session> sessions = new ConcurrentHashMap<String, Session>();
用并发的HashMap 来存放session信息,其中Key 值就是cookie 中对应的jsessionId,如果找到就返回找到的session 对象,如果没有找到并且create 参数是false ,表示不创建session 则 返回null,如果是true 就是创建session 对象,具体的创建session 对象的代码片段为:
//判断cookie 中是否有jsessionId 如果有,就使用这个jsessionId ,如果没有就创建新的jsessionId if (("/".equals(context.getSessionCookiePath()) && isRequestedSessionIdFromCookie()) || requestedSessionSSL) { session = manager.createSession(getRequestedSessionId()); } else { session = manager.createSession(null); } //创建一个新的session cookie,基于刚刚创建好的session if ((session != null) && (getContext() != null) && getContext().getServletContext() .getEffectiveSessionTrackingModes() .contains(SessionTrackingMode.COOKIE)) { Cookie cookie = ApplicationSessionCookieConfig.createSessionCookie( context, session.getIdInternal(), isSecure()); response.addSessionCookieInternal(cookie); }
关于session 中 cookie name 值默认是JSESSIONID ,如果在web.xml 中配置了session-config ,其中cookie-config 下的name 就是sessionCookieName 值,如果没有配置的话,就是默认
具体代码如下:
public static String getSessionCookieName(Context context) { String result = getConfiguredSessionCookieName(context); if (result == null) { result = DEFAULT_SESSION_COOKIE_NAME; } return result; }
具体创建session 的逻辑在ManagerBase 中
public Session createSession(String sessionId) { if ((maxActiveSessions >= 0) && (getActiveSessions() >= maxActiveSessions)) { rejectedSessions++; throw new TooManyActiveSessionsException( sm.getString("managerBase.createSession.ise"), maxActiveSessions); } //创建一个空的session ,其实就是创建org.apache.catalina.session.StandardSession 对象,将该对象交由manager 管理 Session session = createEmptySession(); // Initialize the properties of the new session and return it session.setNew(true); session.setValid(true); session.setCreationTime(System.currentTimeMillis()); session.setMaxInactiveInterval(this.maxInactiveInterval); String id = sessionId; if (id == null) { //生成sessionId,具体的生成SessionId 的逻辑在org.apache.catalina.util.SessionIdGenerator 下的generateSessionId 方法, id = generateSessionId(); } session.setId(id); sessionCounter++; SessionTiming timing = new SessionTiming(session.getCreationTime(), 0); synchronized (sessionCreationTiming) { sessionCreationTiming.add(timing); sessionCreationTiming.poll(); } return (session); }
以上就是创建HttpSession 的过程, 都是个人的理解,由于个人水平有限,还有很多地方没有讲清楚或者说错了,例如session 的持久化技术,具体可以参考 org.apache.catalina.session.StoreBase ,tomcat 提供两种持久化机制,分布是文件持久化,和jdbc 数据持久化 对应的类是FileStore,JDBCStore