最近有兴趣看了tomcat 8源码对session cookie的处理,才发现web.xml支持对session cookie配置maxage,如果不配置默认就是-1,-1表示这个cookie在当前浏览器窗口有效,存放在内存中而不是硬盘,关掉当前浏览器窗口的话,这个cookie失效,会话结束;如果设置了maxage(不等于-1),则存放到硬盘。
部分源码:
org/apache/catalina/connector/Request.java
createSessionCookie:创建一个sessionCookie,并添加到response
protected Session doGetSession(boolean create) {
.................
.................
.................
// 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);
}
.................
.................
.................
}
org/apache/catalina/core/ApplicationSessionCookieConfig.java
private int maxAge = -1; //默认等于-1
scc.getMaxAge():从scc里取得maxAge
package org.apache.catalina.core;
import javax.servlet.SessionCookieConfig;
import javax.servlet.http.Cookie;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.util.SessionConfig;
import org.apache.tomcat.util.res.StringManager;
public class ApplicationSessionCookieConfig implements SessionCookieConfig {
/**
* The string manager for this package.
*/
private static final StringManager sm = StringManager
.getManager(Constants.Package);
private boolean httpOnly;
private boolean secure;
private int maxAge = -1;
private String comment;
private String domain;
private String name;
private String path;
private StandardContext context;
.................
.................
.................
@Override
public int getMaxAge() {
return maxAge;
}
.................
.................
.................
/**
* Creates a new session cookie for the given session ID
*
* @param context The Context for the web application
* @param sessionId The ID of the session for which the cookie will be
* created
* @param secure Should session cookie be configured as secure
* @return the cookie for the session
*/
public static Cookie createSessionCookie(Context context,
String sessionId, boolean secure) {
SessionCookieConfig scc =
context.getServletContext().getSessionCookieConfig();
// NOTE: The priority order for session cookie configuration is:
// 1. Context level configuration
// 2. Values from SessionCookieConfig
// 3. Defaults
Cookie cookie = new Cookie(
SessionConfig.getSessionCookieName(context), sessionId);
// Just apply the defaults.
cookie.setMaxAge(scc.getMaxAge());
cookie.setComment(scc.getComment());
.................
.................
.................
}
}
org/apache/catalina/startup/ContextConfig.java
scc.setMaxAge:读取web.xml里面session-config的max-age并set到scc
package org.apache.catalina.startup;
.................
.................
.................
/**
* Startup event listener for a <b>Context</b> that configures the properties
* of that Context, and the associated defined servlets.
*
* @author Craig R. McClanahan
*/
public class ContextConfig implements LifecycleListener {
.................
.................
.................
/**
* Process a "contextConfig" event for this Context.
*/
protected synchronized void configureStart() {
// Called from StandardContext.start()
if (log.isDebugEnabled()) {
log.debug(sm.getString("contextConfig.start"));
}
if (log.isDebugEnabled()) {
log.debug(sm.getString("contextConfig.xmlSettings",
context.getName(),
Boolean.valueOf(context.getXmlValidation()),
Boolean.valueOf(context.getXmlNamespaceAware())));
}
webConfig();
.................
.................
.................
}
.................
.................
.................
/**
* Scan the web.xml files that apply to the web application and merge them
* using the rules defined in the spec. For the global web.xml files,
* where there is duplicate configuration, the most specific level wins. ie
* an application's web.xml takes precedence over the host level or global
* web.xml file.
*/
protected void webConfig() {
/*
* Anything and everything can override the global and host defaults.
* This is implemented in two parts
* - Handle as a web fragment that gets added after everything else so
* everything else takes priority
* - Mark Servlets as overridable so SCI configuration can replace
* configuration from the defaults
*/
/*
* The rules for annotation scanning are not as clear-cut as one might
* think. Tomcat implements the following process:
* - As per SRV.1.6.2, Tomcat will scan for annotations regardless of
* which Servlet spec version is declared in web.xml. The EG has
* confirmed this is the expected behaviour.
* - As per http://java.net/jira/browse/SERVLET_SPEC-36, if the main
* web.xml is marked as metadata-complete, JARs are still processed
* for SCIs.
* - If metadata-complete=true and an absolute ordering is specified,
* JARs excluded from the ordering are also excluded from the SCI
* processing.
* - If an SCI has a @HandlesType annotation then all classes (except
* those in JARs excluded from an absolute ordering) need to be
* scanned to check if they match.
*/
WebXmlParser webXmlParser = new WebXmlParser(context.getXmlNamespaceAware(),
context.getXmlValidation(), context.getXmlBlockExternal());
Set<WebXml> defaults = new HashSet<>();
defaults.add(getDefaultWebXmlFragment(webXmlParser));
WebXml webXml = createWebXml();
// Parse context level web.xml
InputSource contextWebXml = getContextWebXmlSource();
if (!webXmlParser.parseWebXml(contextWebXml, webXml, false)) {
ok = false;
}
.................
.................
.................
configureContext(webXml);
.................
.................
.................
}
private void configureContext(WebXml webxml) {
.................
.................
.................
SessionConfig sessionConfig = webxml.getSessionConfig();
if (sessionConfig != null) {
if (sessionConfig.getSessionTimeout() != null) {
context.setSessionTimeout(
sessionConfig.getSessionTimeout().intValue());
}
SessionCookieConfig scc =
context.getServletContext().getSessionCookieConfig();
scc.setName(sessionConfig.getCookieName());
scc.setDomain(sessionConfig.getCookieDomain());
scc.setPath(sessionConfig.getCookiePath());
scc.setComment(sessionConfig.getCookieComment());
if (sessionConfig.getCookieHttpOnly() != null) {
scc.setHttpOnly(sessionConfig.getCookieHttpOnly().booleanValue());
}
if (sessionConfig.getCookieSecure() != null) {
scc.setSecure(sessionConfig.getCookieSecure().booleanValue());
}
if (sessionConfig.getCookieMaxAge() != null) {
scc.setMaxAge(sessionConfig.getCookieMaxAge().intValue());
}
if (sessionConfig.getSessionTrackingModes().size() > 0) {
context.getServletContext().setSessionTrackingModes(
sessionConfig.getSessionTrackingModes());
}
}
.................
.................
.................
}
.................
.................
.................
}
org/apache/tomcat/util/descriptor/web/WebRuleSet.java
/session-config/cookie-config/max-age为web.xml的配置项
/**
* <p>Add the set of Rule instances defined in this RuleSet to the
* specified <code>Digester</code> instance, associating them with
* our namespace URI (if any). This method should only be called
* by a Digester instance.</p>
*
* @param digester Digester instance to which the new Rule instances
* should be added.
*/
@Override
public void addRuleInstances(Digester digester) {
.................
.................
.................
digester.addRule(fullPrefix + "/session-config", sessionConfig);
digester.addObjectCreate(fullPrefix + "/session-config",
"org.apache.tomcat.util.descriptor.web.SessionConfig");
digester.addSetNext(fullPrefix + "/session-config", "setSessionConfig",
"org.apache.tomcat.util.descriptor.web.SessionConfig");
digester.addCallMethod(fullPrefix + "/session-config/session-timeout",
"setSessionTimeout", 0);
digester.addCallMethod(fullPrefix + "/session-config/cookie-config/name",
"setCookieName", 0);
digester.addCallMethod(fullPrefix + "/session-config/cookie-config/domain",
"setCookieDomain", 0);
digester.addCallMethod(fullPrefix + "/session-config/cookie-config/path",
"setCookiePath", 0);
digester.addCallMethod(fullPrefix + "/session-config/cookie-config/comment",
"setCookieComment", 0);
digester.addCallMethod(fullPrefix + "/session-config/cookie-config/http-only",
"setCookieHttpOnly", 0);
digester.addCallMethod(fullPrefix + "/session-config/cookie-config/secure",
"setCookieSecure", 0);
digester.addCallMethod(fullPrefix + "/session-config/cookie-config/max-age",
"setCookieMaxAge", 0);
digester.addCallMethod(fullPrefix + "/session-config/tracking-mode",
"addSessionTrackingMode", 0);
.................
.................
.................
}
从上面的addRuleInstances里看出session cookie maxage的配置在工程里的web.xml的session-config里,比如:
<session-config> # 设置Session数据30分钟后过期-服务端 <session-timeout>30</session-timeout> <cookie-config> # 设置SessionId在Cookie中的名称 <name>sop_session_id</name> # 设置SessionId存在哪个路径下,跟路径则可全站使用 <path>/</path> # 设置是否只读 <http-only>true</http-only> # 设置SessionId30分钟后过期 <max-age>1800</max-age> # 设置安全机制,只有https才能获取 <secure>true</secure> </cookie-config> </session-config>
疑问:如果session-timeout和max-age我都设置1年,那不是一年都不用登录了?