Manager<<Interface>>管理Session,负责添加value、持久化等。Manager的实现类必须实现Lifecycle接口。
实现类有StandardManager、PersistentManager、BackupManager等。
StandardManager
SessionId和Session的映射是由一个Map管理的。
/** * The set of currently active Sessions for this Manager, keyed by * session identifier. */ protected Map<String, Session> sessions = new ConcurrentHashMap<>();
Session的持久化是一个名为 SESSIONS.ser 的文件。
/** * Path name of the disk file in which active sessions are saved * when we stop, and from which these sessions are loaded when we start. * A <code>null</code> value indicates that no persistence is desired. * If this pathname is relative, it will be resolved against the * temporary working directory provided by our context, available via * the <code>javax.servlet.context.tempdir</code> context attribute. */ protected String pathname = "SESSIONS.ser";
对Manager正常的使用方法是调用start或stop方法。
start方法
/** * 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 { load(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("standardManager.managerLoad"), t); } setState(LifecycleState.STARTING); }
doLoad方法里,使用了ConcurrentHashMap却又对其加了锁。
- 使用CustomObjectInputStream加载持久化Session文件;
- 将session激活;
- 增加session计数。
stop方法
/** * Stop this component and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected synchronized void stopInternal() throws LifecycleException { if (log.isDebugEnabled()) { log.debug("Stopping"); } setState(LifecycleState.STOPPING); // Write out sessions try { unload(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(sm.getString("standardManager.managerUnload"), t); } // Expire all active sessions Session sessions[] = findSessions(); for (int i = 0; i < sessions.length; i++) { Session session = sessions[i]; try { if (session.isValid()) { session.expire(); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } finally { // Measure against memory leaking if references to the session // object are kept in a shared field somewhere session.recycle(); } } // Require a new random number generator if we are restarted super.stopInternal(); }
调用unload方法,将session过期掉。
在doUnload方法里,使用ObjectOutputStream保存现有sessions,并将sessions过期(重复操作了)。