标签:
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