@Override
public HttpSession getSession() {
if (facade == null){
if (SecurityUtil.isPackageProtectionEnabled()){
final StandardSession fsession = this;
facade = AccessController.doPrivileged(
new PrivilegedAction(){
@Override
public StandardSessionFacade run(){
return new StandardSessionFacade(fsession);
}
});
} else {
// 直接使用 StandardSessionFacade 包装即可
facade = new StandardSessionFacade(this);
}
}
return (facade);
}
再最后,要说明的是,整个sessions的管理使用一个 ConcurrentHashMap 来存放全局会话信息,sessionId->session实例。
对于同一次http请求中,该session会被存储在当前的Request栈org.apache.catalina.connector.Request#session字段中,从而无需每次深入获取。每个请求进来后,会将session保存在当前的request信息中。
3. 过期session清理?
会话不可能不过期,不过期的也不叫会话了。
会话过期的触发时机主要有三个:1. 每次进行会话调用时,会主动有效性isValid()验证,此时如果发现过期可以主动清理: 2. 后台定时任务触发清理; 3. 启动或停止应用的时候清理;(这对于非内存式的存储会更有用些)
// case1. 请求时验证,如前面所述
// org.apache.catalina.connector.Request#doGetSession
protected Session doGetSession(boolean create) {
…
// Return the current session if it exists and is valid
if ((session != null) && !session.isValid()) {
session = null;
}
if (session != null) {
return (session);
}
…
}
// case2. 后台定时任务清理
// org.apache.catalina.session.ManagerBase#backgroundProcess
@Override
public void backgroundProcess() {
// 并非每次定时任务到达时都会进行清理,而是要根据其清理频率设置来运行
// 默认是 6
count = (count + 1) % processExpiresFrequency;
if (count == 0)
processExpires();
}
/**
- Invalidate all sessions that have expired.
*/
public void processExpires() {
long timeNow = System.currentTimeMillis();
// 找出所有的sessions, 转化为数组遍历
Session sessions[] = findSessions();
int expireHere = 0 ;
if(log.isDebugEnabled())
log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length);
for (int i = 0; i < sessions.length; i++) {
// 事实上后台任务也是调用 isValid() 方法 进行过期任务清理的
if (sessions[i]!=null && !sessions[i].isValid()) {
expireHere++;
}
}
long timeEnd = System.currentTimeMillis();
if(log.isDebugEnabled())
log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere);
processingTime += ( timeEnd - timeNow );
}
//case3. start/stop 时触发过期清理(生命周期事件)
// org.apache.catalina.session.StandardManager#startInternal
/**
- Start this component and implement the requirements
- of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
- @exception LifecycleException if this component detects a fatal error
- that prevents this component from being used
*/
@Override
protected synchronized void startInternal() throws LifecycleException {
super.startInternal();
// Load unloaded sessions, if any
try {
// doLoad() 调用
load();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error(sm.getString(“standardManager.managerLoad”), t);
}
setState(LifecycleState.STARTING);
}
/**
- Load any currently active sessions that were previously unloaded
- to the appropriate persistence mechanism, if any. If persistence is not
- supported, this method returns without doing anything.
- @exception ClassNotFoundException if a serialized class cannot be
- found during the reload
- @exception IOException if an input/output error occurs
*/
protected void doLoad() throws ClassNotFoundException, IOException {
if (log.isDebugEna