session作为会话的标识,Servlet容器会把它自动管理起来,在需要的时候创建Session对象。
何时创建session
当我们调用org.apache.catalina.connector.Request的getSession(true) 和changeSessionId(String newSessionId) 方法时,Servlet容器就会尝试创建新的Session。在创建之前会做一些前置检查:
是否已经有session
当前session是否已失效
怎么创建session
确定需要创建session后,默认通过StandardManager 来创建,创建成功后会记录在一个Map 对象中。具体创建逻辑在StandardManager的父类ManagerBase.createSession() 中,代码非常简洁:
public Session createSession(String sessionId) {
if ((maxActiveSessions >= 0) &&
(getActiveSessions() >= maxActiveSessions)) {
rejectedSessions++;
throw new TooManyActiveSessionsException(
sm.getString("managerBase.createSession.ise"),
maxActiveSessions);
}
// Recycle or create a Session instance
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(getContext().getSessionTimeout() * 60);
String id = sessionId;
if (id == null) {
id = generateSessionId();
}
session.setId(id);
sessionCounter++;
SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);
synchronized (sessionCreationTiming) {
sessionCreationTiming.add(timing);
sessionCreationTiming.poll();
}
return session;
}
创建完session后,如果Servlet容器配置的SessionTrackingMode 包含*COOKIE 就会创建一个包含session ID的cookie。*
创建cookie
创建cookie时,有三种方式配置cookie的属性:
根据容器上下文来配置,org.apache.catalina.Context
根据应用自定义信息来配置,jakarta.servlet.SessionCookieConfig
使用默认值
SpringBoot自定义Cookie信息
SpringBoot在application.yml配置文件里可以配置cookie属性,原理是Spring在启动web servlet时,会调用org.springframework.boot.web.servlet.ServletContextInitializer 来初始化容器上下文。其中SessionConfiguringInitializer 就是用来设置cookie信息,它会将application.yml配置文件里的cookie信息塞进SessionCookieConfig 对象里。
SpringBoot配置cookie:
server:
servlet:
session:
cookie:
name: CUSTOM_SESSION
SpringBoot配置SessionCookieConfig :
private void configureSessionCookie(SessionCookieConfig config) {
Session.Cookie cookie = this.session.getCookie();
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
map.from(cookie::getName).to(config::setName);
map.from(cookie::getDomain).to(config::setDomain);
map.from(cookie::getPath).to(config::setPath);
map.from(cookie::getComment).to(config::setComment);
map.from(cookie::getHttpOnly).to(config::setHttpOnly);
map.from(cookie::getSecure).to(config::setSecure);
map.from(cookie::getMaxAge).asInt(Duration::getSeconds).to(config::setMaxAge);
}
org.apache.catalina.connector.Request从SessionCookieConfig获取cookie的名字逻辑:
private static String getConfiguredSessionCookieName(Context context) {
// 优先级:
// 1. 在容器中配置
// 2. 在应用者配置
// 3. 默认值'JSESSIONID'
if (context != null) {
String cookieName = context.getSessionCookieName();
if (cookieName != null && cookieName.length() > 0) {
return cookieName;
}
SessionCookieConfig scc =
context.getServletContext().getSessionCookieConfig();
cookieName = scc.getName();
if (cookieName != null && cookieName.length() > 0) {
return cookieName;
}
}
return null;
}