session是web项目中重要的概念。servlet请求通过session、request等对象保存不同生命周期的数据。
1、session类
servlet解析过程中会涉及到以下几类session信息
StandardSessionFacede被包含在StandardSession中,作为对外暴漏的门面,既能够为servlet展示需要的方法,又屏蔽了一些StandardSession中一些不想暴库的方法。
//session接口的标准实现。这个对象实现了serializable接口,所以他能够在不同的jvm中存储和传输 //session信息,实现了对分布式session的支持 //类实例代表着内部级别和应用级别的session展示。然而因为这个类本身没有被生命为public, // 所以org.apache.catalina.session 包外的java逻辑不能讲httpSession实例返回给Session //如果你为这个类增加属性,你必须确保这个属性覆盖了read/writeObject 方法,以便这个类能够被 //正确的序列化。 class StandardSession implements HttpSession, Session, Serializable { //session关联的管理器manager 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; /** * The <code>java.lang.Method</code> for the * <code>fireContainerEvent()</code> method of the * <code>org.apache.catalina.core.StandardContext</code> method, * if our Context implementation is of this class. This value is * computed dynamically the first time it is needed, or after * a session reload (since it is declared transient). */ private transient Method containerEventMethod = null; /** * The method signature for the <code>fireContainerEvent</code> method. */ private static final Class containerEventTypes[] = { String.class, Object.class }; //session创建时间 private long creationTime = 0L; //debug级别 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; //session的监听器链表 private transient ArrayList listeners = new ArrayList(); //session管理器 private Manager manager = null; //session访问的最大间隔时间,如果超过该时间会该session会置为过期。如果是负数,则表示session永不过期 private int maxInactiveInterval = -1; //标示session是新旧 private boolean isNew = false; //session是否有效 private boolean isValid = false; //关联该session的内部注释 private transient HashMap notes = new HashMap(); //关联该session的授权原则 private transient Principal principal = null; //包描述信息 private static StringManager sm = StringManager.getManager(Constants.Package); //session关联的http session上下文 private static HttpSessionContext sessionContext = null; //该容器的属性变更(不能序列化) /** * The property change support for this component. NOTE: This value * is not included in the serialized version of this object. */ private transient PropertyChangeSupport support = new PropertyChangeSupport(this); //当前访问时间 private long thisAccessedTime = creationTime; public String getAuthType() { return (this.authType); } public void setAuthType(String authType) { String oldAuthType = this.authType; this.authType = authType; //如果authType属性有变化会触发属性变更监听 support.firePropertyChange("authType", oldAuthType, this.authType); } //设置当前时间为创建时间、最后访问时间、当前访问时间 public void setCreationTime(long time) { this.creationTime = time; this.lastAccessedTime = time; this.thisAccessedTime = time; } public String getId() { return (this.id); } public void setId(String id) { if ((this.id != null) && (manager != null)) manager.remove(this); //设置id this.id = id; //管理器管理当前类的门面类。 if (manager != null) manager.add(this); //触发session监听事件 // Notify interested session event listeners fireSessionEvent(Session.SESSION_CREATED_EVENT, null); // 获取容器上下文。 Context context = (Context) manager.getContainer(); //监听器数组 Object listeners[] = context.getApplicationListeners(); if (listeners != null) { HttpSessionEvent event = new HttpSessionEvent(getSession()); for (int i = 0; i < listeners.length; i++) { if (!(listeners[i] instanceof HttpSessionListener)) continue; HttpSessionListener listener = (HttpSessionListener) listeners[i]; try { fireContainerEvent(context, "beforeSessionCreated", listener); //创建session事件 listener.sessionCreated(event); fireContainerEvent(context, "afterSessionCreated", listener); } catch (Throwable t) { try { fireContainerEvent(context, "afterSessionCreated", listener); } catch (Exception e) { ; } // FIXME - should we do anything besides log these? log(sm.getString("standardSession.sessionEvent"), t); } } } } public String getInfo() { return (this.info); } public long getLastAccessedTime() { return (this.lastAccessedTime); } public Manager getManager() { return (this.manager); } public void setManager(Manager manager) { this.manager = manager; } public int getMaxInactiveInterval() { return (this.maxInactiveInterval); } public void setMaxInactiveInterval(int interval) { this.maxInactiveInterval = interval; } public void setNew(boolean isNew) { this.isNew = isNew; } public Principal getPrincipal() { return (this.principal); } public void setPrincipal(Principal principal) { Principal oldPrincipal = this.principal; this.principal = principal; support.firePropertyChange("principal", oldPrincipal, this.principal); } //返回该类的session门面 public HttpSession getSession() { if (facade == null) facade = new StandardSessionFacade(this); return (facade); } //是否合法 public boolean isValid() { return (this.isValid); } public void setValid(boolean isValid) { this.isValid = isValid; } //访问 public void access() { this.isNew = false; this.lastAccessedTime = this.thisAccessedTime; this.thisAccessedTime = System.currentTimeMillis(); } //添加监听器 public void addSessionListener(SessionListener listener) { synchronized (listeners) { listeners.add(listener); } } //是否过期 public void expire() { expire(true); } //过期session实例 public void expire(boolean notify) { // Mark this session as "being expired" if needed if (expiring) return; //标示是否正在做过期动作,如果正在做为true expiring = true; setValid(false); // Remove this session from our manager's active sessions if (manager != null) //删除该session实例 manager.remove(this); //删除属性 String keys[] = keys(); for (int i = 0; i < keys.length; i++) removeAttribute(keys[i], notify); //触发session销毁事件 if (notify) { fireSessionEvent(Session.SESSION_DESTROYED_EVENT, null); } //返回上下文 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); //销毁session 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); } } } // 销毁session过程执行完毕 expiring = false; if ((manager != null) && (manager instanceof ManagerBase)) { recycle(); } } //将session置为非活跃 public void passivate() { // 发送监听消息,触发session非活跃事件 HttpSessionEvent event = null; String keys[] = keys(); for (int i = 0; i < keys.length; i++) { Object attribute = getAttribute(keys[i]); if (attribute instanceof HttpSessionActivationListener) { if (event == null) event = new HttpSessionEvent(this); // FIXME: Should we catch throwables? ((HttpSessionActivationListener)attribute).sessionWillPassivate(event); } } } //激活session public void activate() { // Notify ActivationListeners //触发session激活事件感兴趣的监听器,触发监听事件。 HttpSessionEvent event = null; String keys[] = keys(); for (int i = 0; i < keys.length; i++) { Object attribute = getAttribute(keys[i]); if (attribute instanceof HttpSessionActivationListener) { if (event == null) event = new HttpSessionEvent(this); // FIXME: Should we catch throwables? ((HttpSessionActivationListener)attribute).sessionDidActivate(event); } } } //返回内部制定名称的note信息 public Object getNote(String name) { synchronized (notes) { return (notes.get(name)); } } public Iterator getNoteNames() { synchronized (notes) { return (notes.keySet().iterator()); } } /** *递归清除所有属性值,并恢复为初始值 */ public void recycle() { attributes.clear(); setAuthType(null); creationTime = 0L; expiring = false; id = null; lastAccessedTime = 0L; maxInactiveInterval = -1; notes.clear(); setPrincipal(null); isNew = false; isValid = false; Manager savedManager = manager; manager = null; // Tell our Manager that this Session has been recycled if ((savedManager != null) && (savedManager instanceof ManagerBase)) ((ManagerBase) savedManager).recycle(this); } //删除note public void removeNote(String name) { synchronized (notes) { notes.remove(name); } } //删除session监听 public void removeSessionListener(SessionListener listener) { synchronized (listeners) { listeners.remove(listener); } } //绑定对象到制定的名称上 public void setNote(String name, Object value) { synchronized (notes) { notes.put(name, value); } } public String toString() { StringBuffer sb = new StringBuffer(); sb.append("StandardSession["); sb.append(id); sb.append("]"); return (sb.toString()); } //从特定的输入流读数据 void readObjectData(ObjectInputStream stream) throws ClassNotFoundException, IOException { readObject(stream); } //序列化session对象输出端到stream中 void writeObjectData(ObjectOutputStream stream) throws IOException { writeObject(stream); } public long getCreationTime() { if (!isValid) throw new IllegalStateException (sm.getString("standardSession.getCreationTime.ise")); return (this.creationTime); } /** * Return the ServletContext to which this session belongs. */ //返回和session关联的容器(上下文) public ServletContext getServletContext() { if (manager == null) return (null); Context context = (Context) manager.getContainer(); if (context == null) return (null); else return (context.getServletContext()); } //获得session 关联的session上下文信息 public HttpSessionContext getSessionContext() { if (sessionContext == null) sessionContext = new StandardSessionContext(); return (sessionContext); } //获得属性名称 public Object getAttribute(String name) { if (!isValid) throw new IllegalStateException (sm.getString("standardSession.getAttribute.ise")); synchronized (attributes) { return (attributes.get(name)); } } //获取属性的key值 public Enumeration getAttributeNames() { if (!isValid) throw new IllegalStateException (sm.getString("standardSession.getAttributeNames.ise")); synchronized (attributes) { return (new Enumerator(attributes.keySet())); } } public Object getValue(String name) { return (getAttribute(name)); } public String[] getValueNames() { if (!isValid) throw new IllegalStateException (sm.getString("standardSession.getValueNames.ise")); return (keys()); } //将session实例设置为非法,解绑所有绑定在她上线的对象 public void invalidate() { if (!isValid) throw new IllegalStateException (sm.getString("standardSession.invalidate.ise")); // Cause this session to expire expire(); } public boolean isNew() { if (!isValid) throw new IllegalStateException (sm.getString("standardSession.isNew.ise")); return (this.isNew); } public void putValue(String name, Object value) { setAttribute(name, value); } public void removeAttribute(String name) { removeAttribute(name, true); } //移除指定名称上绑定的属性对象 public void removeAttribute(String name, boolean notify) { // Validate our current state if (!expiring && !isValid) throw new IllegalStateException (sm.getString("standardSession.removeAttribute.ise")); // Remove this attribute from our collection Object value = null; boolean found = false; synchronized (attributes) { found = attributes.containsKey(name); if (found) { value = attributes.get(name); attributes.remove(name); } else { return; } } //是否触发value解绑和属性移除操作 if (!notify) { return; } //调用 valueUnbound()方法 HttpSessionBindingEvent event = new HttpSessionBindingEvent((HttpSession) this, name, value); if ((value != null) && (value instanceof HttpSessionBindingListener)) ((HttpSessionBindingListener) value).valueUnbound(event); //通知感兴趣的事件监听 Context context = (Context) manager.getContainer(); Object listeners[] = context.getApplicationListeners(); if (listeners == null) return; for (int i = 0; i < listeners.length; i++) { if (!(listeners[i] instanceof HttpSessionAttributeListener)) continue; HttpSessionAttributeListener listener = (HttpSessionAttributeListener) listeners[i]; try { fireContainerEvent(context, "beforeSessionAttributeRemoved", listener); //移除属性 listener.attributeRemoved(event); fireContainerEvent(context, "afterSessionAttributeRemoved", listener); } catch (Throwable t) { try { fireContainerEvent(context, "afterSessionAttributeRemoved", listener); } catch (Exception e) { ; } // FIXME - should we do anything besides log these? log(sm.getString("standardSession.attributeEvent"), t); } } } //移除某名称的值 public void removeValue(String name) { removeAttribute(name); } //为属性数组添加key,value public void setAttribute(String name, Object value) { // Name cannot be null if (name == null) throw new IllegalArgumentException (sm.getString("standardSession.setAttribute.namenull")); // Null value is the same as removeAttribute() if (value == null) { removeAttribute(name); return; } // Validate our current state if (!isValid) throw new IllegalStateException (sm.getString("standardSession.setAttribute.ise")); if ((manager != null) && manager.getDistributable() && !(value instanceof Serializable)) throw new IllegalArgumentException (sm.getString("standardSession.setAttribute.iae")); // Replace or add this attribute Object unbound = null; synchronized (attributes) { unbound = attributes.get(name); attributes.put(name, value); } // 触发HttpSessionBindingListener监听 if ((unbound != null) && (unbound instanceof HttpSessionBindingListener)) { ((HttpSessionBindingListener) unbound).valueUnbound (new HttpSessionBindingEvent((HttpSession) this, name)); } // Call the valueBound() method if necessary HttpSessionBindingEvent event = null; if (unbound != null) event = new HttpSessionBindingEvent ((HttpSession) this, name, unbound); else event = new HttpSessionBindingEvent ((HttpSession) this, name, value); if (value instanceof HttpSessionBindingListener) ((HttpSessionBindingListener) value).valueBound(event); // Notify interested application event listeners Context context = (Context) manager.getContainer(); Object listeners[] = context.getApplicationListeners(); if (listeners == null) return; for (int i = 0; i < listeners.length; i++) { if (!(listeners[i] instanceof HttpSessionAttributeListener)) continue; HttpSessionAttributeListener listener = (HttpSessionAttributeListener) listeners[i]; try { if (unbound != null) { fireContainerEvent(context, "beforeSessionAttributeReplaced", listener); //属性值变更 listener.attributeReplaced(event); fireContainerEvent(context, "afterSessionAttributeReplaced", listener); } else { fireContainerEvent(context, "beforeSessionAttributeAdded", listener); //属性值添加 listener.attributeAdded(event); fireContainerEvent(context, "afterSessionAttributeAdded", listener); } } catch (Throwable t) { try { if (unbound != null) { fireContainerEvent(context, "afterSessionAttributeReplaced", listener); } else { fireContainerEvent(context, "afterSessionAttributeAdded", listener); } } catch (Exception e) { ; } // FIXME - should we do anything besides log these? log(sm.getString("standardSession.attributeEvent"), t); } } } //从指定输入流中读序列化信息 private void readObject(ObjectInputStream stream) throws ClassNotFoundException, IOException { // Deserialize the scalar instance variables (except Manager) authType = null; // Transient only creationTime = ((Long) stream.readObject()).longValue(); lastAccessedTime = ((Long) stream.readObject()).longValue(); maxInactiveInterval = ((Integer) stream.readObject()).intValue(); isNew = ((Boolean) stream.readObject()).booleanValue(); isValid = ((Boolean) stream.readObject()).booleanValue(); thisAccessedTime = ((Long) stream.readObject()).longValue(); principal = null; // Transient only // setId((String) stream.readObject()); id = (String) stream.readObject(); if (debug >= 2) log("readObject() loading session " + id); // Deserialize the attribute count and attribute values if (attributes == null) attributes = new HashMap(); int n = ((Integer) stream.readObject()).intValue(); boolean isValidSave = isValid; isValid = true; for (int i = 0; i < n; i++) { String name = (String) stream.readObject(); Object value = (Object) stream.readObject(); if ((value instanceof String) && (value.equals(NOT_SERIALIZED))) continue; if (debug >= 2) log(" loading attribute '" + name + "' with value '" + value + "'"); synchronized (attributes) { attributes.put(name, value); } } isValid = isValidSave; } //写数据到输出流中 private void writeObject(ObjectOutputStream stream) throws IOException { // Write the scalar instance variables (except Manager) stream.writeObject(new Long(creationTime)); stream.writeObject(new Long(lastAccessedTime)); stream.writeObject(new Integer(maxInactiveInterval)); stream.writeObject(new Boolean(isNew)); stream.writeObject(new Boolean(isValid)); stream.writeObject(new Long(thisAccessedTime)); stream.writeObject(id); if (debug >= 2) log("writeObject() storing session " + id); // Accumulate the names of serializable and non-serializable attributes String keys[] = keys(); ArrayList saveNames = new ArrayList(); ArrayList saveValues = new ArrayList(); for (int i = 0; i < keys.length; i++) { Object value = null; synchronized (attributes) { value = attributes.get(keys[i]); } if (value == null) continue; else if (value instanceof Serializable) { saveNames.add(keys[i]); saveValues.add(value); } } // Serialize the attribute count and the Serializable attributes int n = saveNames.size(); stream.writeObject(new Integer(n)); for (int i = 0; i < n; i++) { stream.writeObject((String) saveNames.get(i)); try { stream.writeObject(saveValues.get(i)); if (debug >= 2) log(" storing attribute '" + saveNames.get(i) + "' with value '" + saveValues.get(i) + "'"); } catch (NotSerializableException e) { log(sm.getString("standardSession.notSerializable", saveNames.get(i), id), e); stream.writeObject(NOT_SERIALIZED); if (debug >= 2) log(" storing attribute '" + saveNames.get(i) + "' with value NOT_SERIALIZED"); } } } // -------------------------------------------------------- Private Methods /** * Fire container events if the Context implementation is the * <code>org.apache.catalina.core.StandardContext</code>. * * @param context Context for which to fire events * @param type Event type * @param data Event data * * @exception Exception occurred during event firing */ 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", containerEventTypes); } Object containerEventParams[] = new Object[2]; containerEventParams[0] = type; containerEventParams[1] = data; containerEventMethod.invoke(context, containerEventParams); } /** * Notify all session event listeners that a particular event has * occurred for this Session. The default implementation performs * this notification synchronously using the calling thread. * * @param type Event type * @param data Event data */ public void fireSessionEvent(String type, Object data) { if (listeners.size() < 1) return; SessionEvent event = new SessionEvent(this, type, data); SessionListener list[] = new SessionListener[0]; synchronized (listeners) { list = (SessionListener[]) listeners.toArray(list); } for (int i = 0; i < list.length; i++) ((SessionListener) list[i]).sessionEvent(event); } //属性中的key值 private String[] keys() { String results[] = new String[0]; synchronized (attributes) { return ((String[]) attributes.keySet().toArray(results)); } } //关联他的日志实例打印日志 private void log(String message) { if ((manager != null) && (manager instanceof ManagerBase)) { ((ManagerBase) manager).log(message); } else { System.out.println("StandardSession: " + message); } } //打印错误日志信息 private void log(String message, Throwable throwable) { if ((manager != null) && (manager instanceof ManagerBase)) { ((ManagerBase) manager).log(message, throwable); } else { System.out.println("StandardSession: " + message); throwable.printStackTrace(System.out); } } } //该类是HttpSessionContext的假实现,为了满足HttpSession.getSessionContext()调用返回值信息。 final class StandardSessionContext implements HttpSessionContext { private HashMap dummy = new HashMap(); //返回所有的sessionid信息 数据按照Enumeration类型返回 public Enumeration getIds() { return (new Enumerator(dummy)); } public HttpSession getSession(String id) { return (null); } }
未完待续