标签:
public interface Session {
public static final String SESSION_CREATED_EVENT = "createSession";
public static final String SESSION_DESTROYED_EVENT = "destroySession";
public String getAuthType();
public void setAuthType(String authType);
public long getCreationTime();
public void setCreationTime(long time);
public String getId();
public void setId(String id);
public String getInfo();
public long getLastAccessedTime();
public Manager getManager();
public void setManager(Manager manager);
public int getMaxInactiveInterval();
public void setMaxInactiveInterval(int interval);
public void setNew(boolean isNew);
public Principal getPrincipal();
public void setPrincipal(Principal principal);
public HttpSession getSession();
public void setValid(boolean isValid);
public boolean isValid();
public void access();
public void addSessionListener(SessionListener listener);
public void expire();
public Object getNote(String name);
public Iterator getNoteNames();
public void recycle();
public void removeNote(String name);
public void removeSessionListener(SessionListener listener);
public void setNote(String name, Object value);
}<span style="font-size:18px;">public StandardSession(Manager manager);</span>
class StandardSession
implements HttpSession, Session, Serializable {
public StandardSession(Manager manager) {
super();
this.manager = manager;
if (manager instanceof ManagerBase)
this.debug = ((ManagerBase) manager).getDebug();
}
private static final String NOT_SERIALIZED =
"___NOT_SERIALIZABLE_EXCEPTION___";
private HashMap attributes = new HashMap();
private transient String authType = null;
private transient Method containerEventMethod = null;
private static final Class containerEventTypes[] = { String.class, Object.class };
private long creationTime = 0L;
private transient int debug = 0;
private transient boolean expiring = false;
private transient StandardSessionFacade facade = null;
private String id = null;
private static final String info = "StandardSession/1.0";
private long lastAccessedTime = creationTime;
private transient ArrayList listeners = new ArrayList();
private Manager manager = null;
private int maxInactiveInterval = -1;
private boolean isNew = false;
private boolean isValid = false;
private transient HashMap notes = new HashMap();
private transient Principal principal = null;
private static StringManager sm =
StringManager.getManager(Constants.Package);
private static HttpSessionContext sessionContext = null;
private transient PropertyChangeSupport support =
new PropertyChangeSupport(this);
private long lastUsedTime = creationTime;
}public HttpSession getSession() {
if(facade==null){
facade = new StandardSessionFacade(this);
}
return facade;
}5)设置Session为过期:若Session管理器中的某个Session对象 在某个时间长度内都没有被访问 的话,会被 Session 管理器设置为过期,这个时间长度由变量 maxInactiveInterval 的值来指定;(干货——将一个Session对象设置为过期主要是通过Session接口的expire()
方法来完成的); public void expire(boolean notify) {
// Mark this session as "being expired" if needed
if (expiring)
return;
expiring = true;
setValid(false);
// Remove this session from our manager's active sessions
if (manager != null)
manager.remove(this);
// Unbind any objects associated with this session
String keys[] = keys();
for (int i = 0; i < keys.length; i++)
removeAttribute(keys[i], notify);
// Notify interested session event listeners
if (notify) {
fireSessionEvent(Session.SESSION_DESTROYED_EVENT, null);
}
// Notify interested application event listeners
// FIXME - Assumes we call listeners in reverse order
Context context = (Context) manager.getContainer();
Object listeners[] = context.getApplicationListeners();
if (notify && (listeners != null)) {
HttpSessionEvent event =
new HttpSessionEvent(getSession());
for (int i = 0; i < listeners.length; i++) {
int j = (listeners.length - 1) - i;
if (!(listeners[j] instanceof HttpSessionListener))
continue;
HttpSessionListener listener =
(HttpSessionListener) listeners[j];
try {
fireContainerEvent(context, // highlight line.
"beforeSessionDestroyed",
listener);
listener.sessionDestroyed(event); // destroy session.
fireContainerEvent(context, // also highlight line.
"afterSessionDestroyed",
listener);
} catch (Throwable t) {
try {
fireContainerEvent(context,
"afterSessionDestroyed",
listener);
} catch (Exception e) {
;
}
// FIXME - should we do anything besides log these?
log(sm.getString("standardSession.sessionEvent"), t);
}
}
}
// We have completed expire of this session
expiring = false;
if ((manager != null) && (manager instanceof ManagerBase)) {
recycle();
} } private void fireContainerEvent(Context context,
String type, Object data)
throws Exception {
if (!"org.apache.catalina.core.StandardContext".equals
(context.getClass().getName())) {
return; // Container events are not supported
}
// NOTE: Race condition is harmless, so do not synchronize
if (containerEventMethod == null) {
containerEventMethod =
context.getClass().getMethod("fireContainerEvent", // terrific line.
containerEventTypes);
}
Object containerEventParams[] = new Object[2];
containerEventParams[0] = type;
containerEventParams[1] = data;
containerEventMethod.invoke(context, containerEventParams);
}
public interface Manager {
public Container getContainer();
public void setContainer(Container container);
public DefaultContext getDefaultContext();
public void setDefaultContext(DefaultContext defaultContext);
public boolean getDistributable();
public void setDistributable(boolean distributable);
public String getInfo();
public int getMaxInactiveInterval();
public void setMaxInactiveInterval(int interval);
public void add(Session session);
public Session createEmptySession();
public void addPropertyChangeListener(PropertyChangeListener listener);
public Session createSession();
public Session findSession(String id) throws IOException;
public Session[] findSessions();
public void load() throws ClassNotFoundException, IOException;
public void remove(Session session);
public void removePropertyChangeListener(PropertyChangeListener listener);
public void unload() throws IOException;
}A1)getContainer()方法和setContainer()方法:以便将一个Manager实现与一个 Context容器相关联;A2)createSession()方法:用来创建一个Session实例;A3)add()方法:会将一个 Session实例添加到 Session池中;A4)remove()方法:则会将一个 Session实例从 Session池中移除;A5)getMaxInactiveInterval()方法和 setMaxInactiveInterval()方法:用来获取或设置一个时间长度,单位为秒;A6)Session管理器: 会以此作为一个Session对象的最长存活时间;A7)load()方法和unload() 方法:用来将Session对象持久化到辅助存储器中(干货——load方法和unload方法)
A7.1)load方法:该方法会将介质中的Session对象重新载入到内存中;A7.2)unload方法:该方法会将当前活动的 Session对象存储到 Manager 实现指定的介质中;
protected HashMap sessions = new HashMap();
public void add(Session session) {
synchronized (sessions) {
sessions.put(session.getId(), session);
if( sessions.size() > maxActive ) {
maxActive=sessions.size();
}
}
}
public void remove(Session session) {
synchronized (sessions) {
sessions.remove(session.getId());
}
}
public Session[] findSessions() {
Session results[] = null;
synchronized (sessions) {
results = new Session[sessions.size()];
results = (Session[]) sessions.values().toArray(results);
}
return (results);
}
public Session findSession(String id) throws IOException {
if (id == null)
return (null);
synchronized (sessions) {
Session session = (Session) sessions.get(id);
return (session);
}
} public void run() { //org.apache.catalina.session.StandardManager
// Loop until the termination semaphore is set
while (!threadDone) {
threadSleep();
processExpires();
}
}A1)threadSleep()方法:会使线程休眠一段时间,长度由checkInterval指定,default==60 秒;A2)processExpir()方法:会遍历由 Session管理器管理的所有Session对象,将Session实例的lastAccessedTime属性值与当前时间进行比较,如果两者之间的差值超过了变量 maxInactiveInterval 指定的数值,则会调用 Session接口的 expire() 方法使这个Session实例过期;private void processExpires() { // org.apache.catalina.session.StandardManager.processExpires() long timeNow = System.currentTimeMillis(); Session sessions[] = findSessions(); for (int i = 0; i < sessions.length; i++) { StandardSession session = (StandardSession) sessions[i]; if (!session.isValid()) continue; int maxInactiveInterval = session.getMaxInactiveInterval(); if (maxInactiveInterval < 0) continue; int timeIdle = // Truncate, do not round up (int) ((timeNow - session.getLastUsedTime()) / 1000L); if (timeIdle >= maxInactiveInterval) { try { expiredSessions++; session.expire();// highlight line. } catch (Throwable t) { log(sm.getString("standardManager.expireException"), t); } } } }
A1)在tomcat5中,StandardManager类已不再实现 java.lang.Runnable接口。其中的 backgroundporocess() 方法会直接调用 tomcat5 中StandardManager对象的 processExpires()方法;
public voiid backgroundProcess() { //org.apache.catalina.session.StandardManager.backgroundProcess() processExpire(); }
public void expire() { //org.apache.catalina.sessoin.StandardManager.expire() expire(true); } public void expire(boolean notify) { // the same as the above. // Mark this session as "being expired" if needed if (expiring) return; expiring = true; setValid(false); // Remove this session from our manager's active sessions if (manager != null) manager.remove(this); // Unbind any objects associated with this session String keys[] = keys(); for (int i = 0; i < keys.length; i++) removeAttribute(keys[i], notify); // Notify interested session event listeners if (notify) { fireSessionEvent(Session.SESSION_DESTROYED_EVENT, null); } // Notify interested application event listeners // FIXME - Assumes we call listeners in reverse order Context context = (Context) manager.getContainer(); Object listeners[] = context.getApplicationListeners(); if (notify && (listeners != null)) { HttpSessionEvent event = new HttpSessionEvent(getSession()); for (int i = 0; i < listeners.length; i++) { int j = (listeners.length - 1) - i; if (!(listeners[j] instanceof HttpSessionListener)) continue; HttpSessionListener listener = (HttpSessionListener) listeners[j]; try { fireContainerEvent(context, "beforeSessionDestroyed", listener); listener.sessionDestroyed(event); fireContainerEvent(context, "afterSessionDestroyed", listener); } catch (Throwable t) { try { fireContainerEvent(context, "afterSessionDestroyed", listener); } catch (Exception e) { ; } // FIXME - should we do anything besides log these? log(sm.getString("standardSession.sessionEvent"), t); } } } // We have completed expire of this session expiring = false; if ((manager != null) && (manager instanceof ManagerBase)) { recycle(); } }
public void run() { //org.apache.catalina.session.PersistentManagerBase.run()
while(!threadDone) {
threadSleep();
processExpires(); // 检查Session对象是否过期.
processPersistenceChecks();
}
}
public void processPersistenceChecks(){ // org.apache.catalina.session.PersistentManagerBase.processPersistenceChecks()
processMaxIdleSwaps(); // highlight line.(下面我们只以processMaxIdleSwaps方法为例进行调用过程的分析,其他两个方法类似)
processMaxActiveSwaps(); // highlight line.
processMaxIdleBackups(); // highlight line.
}/**
* Swap idle sessions out to Store if they are idle too long.若session空闲太久则换出
*/
protected void processMaxIdleSwaps() {
if (!isStarted() || maxIdleSwap < 0)
return;
Session sessions[] = findSessions();
long timeNow = System.currentTimeMillis();
// Swap out all sessions idle longer than maxIdleSwap
// FIXME: What's preventing us from mangling a session during
// a request?
if (maxIdleSwap >= 0) {
for (int i = 0; i < sessions.length; i++) {
StandardSession session = (StandardSession) sessions[i];
if (!session.isValid())
continue;
long lastAccessed = ((StandardSession)session).getLastUsedTime();
int timeIdle = // Truncate, do not round up
(int) ((timeNow - lastAccessed) / 1000L);
if (timeIdle > maxIdleSwap && timeIdle > minIdleSwap) {
if (debug > 1)
log(sm.getString
("persistentManager.swapMaxIdle",
session.getId(), new Integer(timeIdle)));
try {
swapOut(session); // highlight line.
} catch (IOException e) {
; // This is logged in writeSession()
}
}
}
}
}protected void swapOut(Session session) throws IOException { //换出操作
if (store == null ||
!session.isValid() ||
isSessionStale(session, System.currentTimeMillis()))
return;
((StandardSession)session).passivate();
writeSession(session); // highlight line.
super.remove(session);
session.recycle();
}protected void writeSession(Session session) throws IOException {
if (store == null ||
!session.isValid() ||
isSessionStale(session, System.currentTimeMillis()))
return;
try {
store.save(session); //highlight line.
sessionSwapIgnore.remove(session.getId());
} catch (IOException e) {
log(sm.getString
("persistentManager.serializeError", session.getId(), e));
throw e;
}
}4.1.1)当活动的Session实例数量过多时:PersistentManagerBase会将Session对象换出直到数量等于 maxActiveSessions;(参见 processMaxActiveSwaps()方法)4.1.2)当某个Session对象闲置了过长时间:PersistentManagerBase会依据两个变量来决定是否将这个Session换出,这两个变量是minIdleSwap and maxIdleSwap;如果某个Session对象的 lastAccessedTime 属性的值超过了 minIdleSwap 和 maxIdleSwap 的值,就会将这个Session换出;(干货——为了防止换出Session对象,将maxIdleSwap设置为负数,参见 processMaxIdleSwaps() 方法);
public Session findSession(String id) throws IOException { //org.apache.catalina.session.PersistentManagerBase.findSession()
Session session = super.findSession(id);
if (session != null)
return (session);
// See if the Session is in the Store
session = swapIn(id); // highlight line.
return (session);
}protected Session swapIn(String id) throws IOException { // the same as the above.
if (store == null)
return null;
if (sessionSwapIgnore.contains(id)) {
return null;
}
Session session = null;
try {
session = store.load(id); // highlight line.
} catch (ClassNotFoundException e) {
log(sm.getString("persistentManager.deserializeError", id, e));
throw new IllegalStateException
(sm.getString("persistentManager.deserializeError", id, e));
}
if (session == null) {
sessionSwapIgnore.put(id,id);
return (null);
}
if (!session.isValid()
|| isSessionStale(session, System.currentTimeMillis())) {
log("session swapped in is invalid or expired");
session.expire(); // highlight line.
store.remove(id); // highlight line.
sessionSwapIgnore.put(id,id);
return (null);
}
if(debug > 2)
log(sm.getString("persistentManager.swapIn", id));
session.setManager(this);
// To make sure the listener knows about it.
((StandardSession)session).tellNew();
add(session);
((StandardSession)session).activate();
return (session);
}public final class PersistentManager extends PersistentManagerBase { //org.apache.catalina.session.PersistentManager
private static final String info = "PersistentManager/1.0";
protected static String name = "PersistentManager";
public String getInfo() {
return (this.info);
}
public String getName() {
return (name);
}
} public Session createSession() {
Session session = super.createSession(); // step1.
ObjectOutputStream oos = null;
ByteArrayOutputStream bos = null;
ByteArrayInputStream bis = null;
try {
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(new BufferedOutputStream(bos));
((StandardSession)session).writeObjectData(oos);
oos.close();
byte[] obs = bos.toByteArray();
clusterSender.send(obs); // step2.
if(debug > 0)
log("Replicating Session: "+session.getId());
} catch (IOException e) {
log("An error occurred when replicating Session: "+session.getId());
}
return (session);
}step1)调用超类的 createSession()方法为自身创建一个 Session对象;step2)使用ClusterSender实例,以字节数组的形式将该Session对象发送到集群中的其他节点;
public void run() { // org.apache.catalina.session.DistributedManager.run()
// Loop until the termination semaphore is set
while (!threadDone) {
threadSleep();
processClusterReceiver(); // 以该方法为例进行说明.
processExpires();
processPersistenceChecks();
}
}/**
* Called from our background thread to process new received Sessions
*
*/
public void processClusterReceiver() { //org.apache.catalina.session.DistributedManager.processClusterReceiver()
Object[] objs = clusterReceiver.getObjects();
StandardSession _session = null;
ByteArrayInputStream bis = null;
Loader loader = null;
ClassLoader classLoader = null;
ObjectInputStream ois = null;
byte[] buf = new byte[5000];
ReplicationWrapper repObj = null;
for(int i=0; i < objs.length;i++) {
try {
bis = new ByteArrayInputStream(buf);
repObj = (ReplicationWrapper)objs[i];
buf = repObj.getDataStream();
bis = new ByteArrayInputStream(buf, 0, buf.length);
if (container != null)
loader = container.getLoader();
if (loader != null)
classLoader = loader.getClassLoader();
if (classLoader != null)
ois = new CustomObjectInputStream(bis,
classLoader);
else
ois = new ObjectInputStream(bis);
_session = (StandardSession) super.createSession();
_session.readObjectData(ois);
_session.setManager(this);
if (debug > 0)
log("Loading replicated session: "+_session.getId());
} catch (IOException e) {
log("Error occurred when trying to read replicated session: "+
e.toString());
} catch (ClassNotFoundException e) {
log("Error occurred when trying to read replicated session: "+
e.toString());
} finally {
if (ois != null) {
try {
ois.close();
bis = null;
} catch (IOException e) {
;
}
}
}
}
}public interface Store { // org.apache.catalina.Store
public String getInfo();
public Manager getManager();
public void setManager(Manager manager);
public int getSize() throws IOException;
public void addPropertyChangeListener(PropertyChangeListener listener);
public String[] keys() throws IOException;
public Session load(String id)
throws ClassNotFoundException, IOException;
public void remove(String id) throws IOException;
public void clear() throws IOException;
public void removePropertyChangeListener(PropertyChangeListener listener);
public void save(Session session) throws IOException;
} 
public void run() { // org.apache.catalina.session.StoreBase.run()
// Loop until the termination semaphore is set
while (!threadDone) {
threadSleep();
processExpires();
}
}A1)processExpires方法:会获取所有活动的 Session对象,检查 每个Session对象的 lastAccessedTime属性值,删除那些长时间不活动的Session对象;源代码如下:(干货——再次提及了processExpires方法,注意其功能)
protected void processExpires() {// org.apache.catalina.session.StoreBase.processExpires() long timeNow = System.currentTimeMillis(); String[] keys = null; if(!started) { return; } try { keys = keys(); } catch (IOException e) { log (e.toString()); e.printStackTrace(); return; } for (int i = 0; i < keys.length; i++) { try { StandardSession session = (StandardSession) load(keys[i]); if (session == null) { continue; } if (!session.isValid()) { continue; } int maxInactiveInterval = session.getMaxInactiveInterval(); if (maxInactiveInterval < 0) { continue; } int timeIdle = // Truncate, do not round up (int) ((timeNow - session.getLastUsedTime()) / 1000L); if (timeIdle >= maxInactiveInterval) { if ( ( (PersistentManagerBase) manager).isLoaded( keys[i] )) { // recycle old backup session session.recycle(); } else { // expire swapped out session session.expire(); } remove(session.getId()); } } catch (Exception e) { log ("Session: "+keys[i]+"; "+e.toString()); try { remove(keys[i]); } catch (IOException e2) { log (e2.toString()); e2.printStackTrace(); } } } }
public class SessionServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("SessionServlet -- service");
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head><title>SessionServlet</title></head>");
out.println("<body>");
String value = request.getParameter("value");
HttpSession session = request.getSession(true);
out.println("<br>the previous value is " +
(String) session.getAttribute("value"));
out.println("<br>the current value is " + value);
session.setAttribute("value", value);
out.println("<br><hr>");
out.println("<form>");
out.println("New Value: <input name=value>");
out.println("<input type=submit>");
out.println("</form>");
out.println("</body>");
out.println("</html>");
}
} public static void main(String[] args) {
//invoke: http://localhost:8080/myApp/Session
System.setProperty("catalina.base", System.getProperty("user.dir"));
Connector connector = new HttpConnector();
Wrapper wrapper1 = new SimpleWrapper();
wrapper1.setName("Session");
wrapper1.setServletClass("SessionServlet");
Context context = new StandardContext();
// StandardContext's start method adds a default mapper
context.setPath("/myApp");
context.setDocBase("myApp");
context.addChild(wrapper1);
// context.addServletMapping(pattern, name);
// note that we must use /myApp/Session, not just /Session
// because the /myApp section must be the same as the path, so the cookie will
// be sent back.
context.addServletMapping("/myApp/Session", "Session");
// add ContextConfig. This listener is important because it configures
// StandardContext (sets configured to true), otherwise StandardContext
// won't start
LifecycleListener listener = new SimpleContextConfig();
((Lifecycle) context).addLifecycleListener(listener);
// here is our loader
Loader loader = new WebappLoader();
// associate the loader with the Context
context.setLoader(loader);
connector.setContainer(context);
// add a Manager
Manager manager = new StandardManager(); // highlight line.
context.setManager(manager); // highlight line.
try {
connector.initialize();
((Lifecycle) connector).start();
((Lifecycle) context).start();
// make the application wait until we press a key.
System.in.read();
((Lifecycle) context).stop();
}
catch (Exception e) {
e.printStackTrace();
}
}
} public void invoke(Request request, Response response, ValveContext valveContext)
throws IOException, ServletException {
SimpleWrapper wrapper = (SimpleWrapper) getContainer();
ServletRequest sreq = request.getRequest();
ServletResponse sres = response.getResponse();
Servlet servlet = null;
HttpServletRequest hreq = null;
if (sreq instanceof HttpServletRequest)
hreq = (HttpServletRequest) sreq;
HttpServletResponse hres = null;
if (sres instanceof HttpServletResponse)
hres = (HttpServletResponse) sres;
//-- new addition -----------------------------------
Context context = (Context) wrapper.getParent(); // highlight line.
request.setContext(context); // highlight line.
//-------------------------------------
// Allocate a servlet instance to process this request
try {
servlet = wrapper.allocate();
if (hres!=null && hreq!=null) {
servlet.service(hreq, hres);
}
else {
servlet.service(sreq, sres);
}
}
catch (ServletException e) {
}
}Manager manager = null;
if(contect != null)
manager = context.getManager();E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src>java -cp .;lib/servlet.jar;lib/catalina_4_1_24.jar;lib/catalina-5.5.4.jar;lib/naming-common. jar;lib/commons-collections.jar;lib/naming-resources.jar;lib/;lib/catalina.jar;E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\webroot com/tomca t/chapter9/startup/Bootstrap HttpConnector Opening server socket on all host IP addresses HttpConnector[8080] Starting background thread WebappLoader[/myApp]: Deploying class repositories to work directory E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src\work\_\_\myApp Starting Wrapper Session StandardManager[/myApp]: Seeding random number generator class java.security.SecureRandom StandardManager[/myApp]: Seeding of random number generator has been completed SessionServlet -- service SessionServlet -- service SessionServlet -- service SessionServlet -- service
标签:
原文地址:http://blog.csdn.net/pacosonswjtu/article/details/51231894