HttpServletRequest接口中getSession()方法有3种用法,说明如下:
request.getSession()就是request.getSession(true)。request.getSession(false)与上二者的区别在于,如果当前Context中没有Session时(如用户第一次访问网站时),并不创建新Session对象,直接返回null。
以下根据tomcat-8.0.24中的源码进行简单说明。
getSession()与getSession(true)
从这个org.apache.catalina.connector.RequestFacade类中可以看到getSession()方法其实就是调用getSession(true)。
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); }}public HttpSession getSession() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return getSession(true);} |
getSession(false)
上面的方法会调用此org.apache.catalina.connector.Request类中的getSession()和doGetSession(true)方法,然后由session.getSession()返回结果。
如果是getSession(false),则会进入doGetSession(false)方法,当用户初次访问时,requestedSessionId为空,所以session为null,因为此时参数create传入的值为false,所以直接返回null。
public HttpSession getSession() { Session session = doGetSession(true); if (session == null) { return null; } return session.getSession();}public HttpSession getSession(boolean create) { Session session = doGetSession(create); if (session == null) { return null; } return session.getSession();}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) { // request.getSession(false)时,在此返回null return (null); } if (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 && context.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;} |
findSession(String)
再通过org.apache.catalina.session.ManagerBase看一下servlet是如何通过requestedSessionId查找到对应的用户session的,由下面代码可以看到tomcat中用户session使用ConcurrentHashMap作为容器进行管理的。
/** * Return the active Session, associated with this Manager, with the specified session id (if any); otherwise return null. * Parameters: * id The session id for the session to be returned * Throws: * java.lang.IllegalStateException if a new session cannot be instantiated for any reason * java.io.IOException if an input/output error occurs while processing this request */public Session findSession(String id) throws IOException { if (id == null) return (null); return sessions.get(id);}/** * The set of currently active Sessions for this Manager, keyed by session identifier. */protected Map<String, Session> sessions = new ConcurrentHashMap<>(); |
favicon.ico和session
在浏览器中访问favicon.ico文件时,HTTP请求的header中不会发送用户当前的cookie信息,当服务器上使用MVC的拦截器时,就需要注意,不要拦截这个favicon.ico文件,因为在这个请求中不能获得用户的session,因此也不要在拦截器中使用request.getSession()方法来获得session,不小心可能会重置用户的session,最好是使用request.getSession(false)方法。