《How Tomcat Works》读书笔记(九)Session Management
2013-03-18 14:15
573 查看
通常,每一个部署在Tomcat上的Web项目(Context)都会有一个会话管理器与之关联。负责会话的创建、获取、更新、删除。
下面来个简单的示例:
Session Manager默认在内存中存放Session对象,它还可以持久化Session对象到文件或数据库中。本文后面会介绍。
在servlet编程中,一个session对象由javax.servlet.http.HttpSession接口表示,在一个Manager中,一个session对象由org.apache.catalina.Session接口表示。
StandardSession实现了javax.servlet.http.HttpSession和org.apache.catalina.Session接口。
我们通过javax.servlet.http.HttpServletRequest的HttpSession getSession()方法可以获取当前会话。
出于安全考虑,Manager传递给我们的是一个叫做StandardSessionFacade类(只实现了javax.servlet.http.HttpSession接口),而不是StandardSession,这样做可以有效防止servlet开发者调用他不该看到的定义在org.apache.catalina.Session接口中的方法。
他们的关系如图:
Session接口
StandardSessionFacade是StandardSession作为HttpSession时的Facade。
Manager也和一个Facade一起工作:Session
StandardSession
Session过期
Manager中会定义一个maxInactiveInterval变量,当一个session超过
maxInactiveInterval时间没有被访问就视为过期。
Manager维护的一个后台线程会调用session的expire方法
Manger
Manager负责管理session,org.apache.catalina.session包中有一个抽象类ManagerBase,它有两个子类StandardManager、PersistentManagerBase。
StandardManager运行时:把session存放在内存中;停止时:把session存放在一个文件中,当再一次启动时,从文件中把session恢复到内存中来。
PersistentManagerBase:把session存放在二级存储中,如硬盘。它有两个子类PersistentManager、DistributedManager。
Manager接口:
PersistentManagerBase
PersistentManagerBase用一个
Store代表存放session对象的二级存储。
备份(back up)到Store,并且可以从Store中
换出 (swap out)。
他们两个的区别在于:back up是内存、Store各有一份;swap out:仅Store里有一份。
DistributedManager
DistributedManager在集群环境(两台以上机器)中使用。在集群中会有一个个结点(Node),不同的结点可以在一台机器中,也可以在不同机器中。在集群环境中,每一个结点必须拥有一个DistributedManager实例作为结点的Manager,负责Session同步(复制)。
当一个Session对象建立/销毁的时候,它所在的结点就要通知其他结点进行复制/销毁。
Tomcat提供了两个类来收发通知:ClusterSender发送通知,ClusterReceiver接收通知。
Store接口
StoreBase是一个抽象类,为两个子类提供了一些通用的方法,但是没有实现save和load方法,因为他们依赖于不同类型的存储。
FileStore代表文件存储:使用java.io.ObjectOutputStream来序列化session,java.io.ObjectInputStream来反序列化session。
JDBCStore代表数据库存储。
下面来个简单的示例:
Manager manager = null; if (context != null) manager = context.getManager();//从Context中获取Manager if (manager == null) return (null); if (requestedSessionId != null) { try { //manager根据sessionid获取session session = manager.findSession(requestedSessionId); }catch (IOException e) { session = null; } if ((session != null) && !session.isValid()) session = null; if (session != null) { return (session.getSession()); } } if (!create) return (null); ... session = manager.createSession();//manager创建session if (session != null) return (session.getSession()); else return (null); }
Session Manager默认在内存中存放Session对象,它还可以持久化Session对象到文件或数据库中。本文后面会介绍。
在servlet编程中,一个session对象由javax.servlet.http.HttpSession接口表示,在一个Manager中,一个session对象由org.apache.catalina.Session接口表示。
StandardSession实现了javax.servlet.http.HttpSession和org.apache.catalina.Session接口。
我们通过javax.servlet.http.HttpServletRequest的HttpSession getSession()方法可以获取当前会话。
出于安全考虑,Manager传递给我们的是一个叫做StandardSessionFacade类(只实现了javax.servlet.http.HttpSession接口),而不是StandardSession,这样做可以有效防止servlet开发者调用他不该看到的定义在org.apache.catalina.Session接口中的方法。
他们的关系如图:
Session接口
StandardSessionFacade是StandardSession作为HttpSession时的Facade。
Manager也和一个Facade一起工作:Session
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();//id作为一个session对象在Context中的唯一标示 public void setId(String id); public String getInfo(); public long getLastAccessedTime();//Manager调用这个方法判断session是否过期、非法 public Manager getManager();//一个session对象通常包含在一个Manager中 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); }
StandardSession
//实现java.lang.Serializable接口使session可序列化,反序列化 public class StandardSession implements Serializable{ //构造方法,强制与一个Manager关联 public StandardSession(Manager manager){ this.manager = manager; } //session属性 private HashMap attributes = new HashMap(); private transient String authType = null;//transient表示不进行序列化的属性 private long creationTime = 0L; private transient boolean expiring = false; private transient StandardSessionFacade facade = null; private String id = null; 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 long thisAccessedTime = creationTime; ...... public HttpSession getSession() { if (facade == null) facade = new StandardSessionFacade(this);//返回一个Facade return (facade); } }
Session过期
Manager中会定义一个maxInactiveInterval变量,当一个session超过
maxInactiveInterval时间没有被访问就视为过期。
Manager维护的一个后台线程会调用session的expire方法
public void expire(boolean notify) { if (expiring) return;//已过期标示 expiring = true; setValid(false); if (manager != null) manager.remove(this);//从Manager管理的活跃会话中删除 String keys [] = keys(); for(int i = 0; i < keys.length; i++) removeAttribute(keys[i], notify);//把与session关联的对象解绑 if (notify) {//通知对SESSION_DESTROYED_EVENT感兴趣的监听器 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); listener.sessionDestroyed(event); fireContainerEvent(context, "afterSessionDestroyed", listener); } catch (Throwable t) { try { fireContainerEvent(context, "afterSessionDestroyed", listener); }catch(Exception e}{ ; } log(sm.getString("standardSession.sessionEvent"), t); } } } expiring = false; if ((manager != null) && (manager instanceof ManagerBase)){ recycle(); } }
Manger
Manager负责管理session,org.apache.catalina.session包中有一个抽象类ManagerBase,它有两个子类StandardManager、PersistentManagerBase。
StandardManager运行时:把session存放在内存中;停止时:把session存放在一个文件中,当再一次启动时,从文件中把session恢复到内存中来。
PersistentManagerBase:把session存放在二级存储中,如硬盘。它有两个子类PersistentManager、DistributedManager。
Manager接口:
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);//加入到session pool中 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;//存放到特定存储中 }ManagerBase:
public abstract class ManagerBase implements Manager { ...... protected HashMap sessions = new HashMap(); public void add(Session session) { synchronized (sessions) { sessions.put(session.getId(), session); } } public void remove(Session session) { synchronized (sessions) { sessions.remove(session.getId()); } } public Session findSession(String id) throws IOException { if (id == null) return (null); synchronized (sessions) { Session session = (Session) sessions.get(id); return (session); } } ...... }
PersistentManagerBase
PersistentManagerBase用一个
Store代表存放session对象的二级存储。
private Store store = null;session对象可以
备份(back up)到Store,并且可以从Store中
换出 (swap out)。
他们两个的区别在于:back up是内存、Store各有一份;swap out:仅Store里有一份。
DistributedManager
DistributedManager在集群环境(两台以上机器)中使用。在集群中会有一个个结点(Node),不同的结点可以在一台机器中,也可以在不同机器中。在集群环境中,每一个结点必须拥有一个DistributedManager实例作为结点的Manager,负责Session同步(复制)。
当一个Session对象建立/销毁的时候,它所在的结点就要通知其他结点进行复制/销毁。
Tomcat提供了两个类来收发通知:ClusterSender发送通知,ClusterReceiver接收通知。
public Session createSession() { Session session = super.createSession(); ObjectOutputStream oos = null; ByteArrayOutputStream bos = null; ByteArraylnputStream 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); if(debug > 0) log("Replicating Session: "+session.getId()); } catch (IOException e) { log("An error occurred when replicating Session: " + session.getId()); } retun (session); }同时,DistribubedManager实现了java.lang.Runnable来确保有一个单独的线程接收其它结点发来的消息。
public void run() { while (!threadDone) { threadSleep(); processClusterReceiver(); processExpires(); processPersistenceChecks(); } }
Store接口
public interface 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; pubiic void removePropertyChangeListener(PropertyChangeListener listener); public void save(Session session) throws IOException; }
StoreBase是一个抽象类,为两个子类提供了一些通用的方法,但是没有实现save和load方法,因为他们依赖于不同类型的存储。
FileStore代表文件存储:使用java.io.ObjectOutputStream来序列化session,java.io.ObjectInputStream来反序列化session。
JDBCStore代表数据库存储。
相关文章推荐
- 《How Tomcat Works》读书笔记(四)
- how tomcat works 读书笔记(一)----------一个简单的web服务器
- How tomcat works 读书笔记十二 StandardContext 上
- 《How Tomcat Works》读书笔记(五):生命周期
- how tomcat works 读书笔记(一)----------一个简单的web服务器
- how tomcat works 读书笔记(二)----------一个简单的servlet容器
- How tomcat works 读书笔记十二 StandardContext 上
- 《How Tomcat Works》读书笔记(三)Connector
- how tomcat works 读书笔记(二)----------一个简单的servlet容器
- 《How Tomcat Works》读书笔记一
- How tomcat works 读书笔记十七 启动tomcat 下
- 《How Tomcat Works》读书笔记(二)A Simple Servlet Conta...
- 《How Tomcat Works》读书笔记(七)Logger
- how tomcat works 读书笔记九 Session管理
- How tomcat works 读书笔记十七 启动tomcat 下
- 《How Tomcat Works》读书笔记(四)Tomcat Default Connector
- how tomcat works 读书笔记 十一 StandWrapper 上
- how tomcat works 读书笔记 八 载入器下
- 《How Tomcat Works》读书笔记(一)
- 《How Tomcat Works》读书笔记(三):Tomcat default connector