读书人

Coder 爱通译 How Tomcat Works 第九章

发布时间: 2012-09-05 15:19:34 作者: rapoo

Coder 爱翻译 How Tomcat Works 第九章 第一部分
Chapter 9: Session Management

Catalina通过一个叫做manager的组件来支持session管理。manager是由org.apache.catalina.Manager接口表示。一个manager总是和一个context相关联的。manager负责创建、更新、销毁(使一个session失效)session对象和返回一个有效的session对象给请求组件。

servlet可以通过调用javax.servlet.http.HttpServletRequest接口的getSession方法来获取一个session对象。在默认连接器中org.apache.catalina.connector.HttpRequestBase类实现了HttpServletRequest接口。

public HttpSession getSession() {    return (getSession(true)); } public HttpSession getSession(boolean create) {    ...    return doGetSession(create); } private HttpSession doGetSession(boolean create) {    // There cannot be a session if no context has been assigned yet    if (context == null)      return (null);    // Return the current session if it exists and is valid    if ((session != null) && !session.isValid())      session = null;    if (session != null)      return (session.getSession());   // Return the requested session if it exists and is valid   Manager manager = null;    if (context != null)      manager = context.getManager();    if (manager == null)       return (null);      // Sessions are not supported    if (requestedSessionId != null) {      try {        session = manager.findSession(requestedSessionId);      }      catch (IOException e) {        session = null;      }      if ((session != null) && !session.isValid())        session = null;      if (session != null) {        return (session.getSession());      }    }    // Create a new session if requested and the response is not    // committed    if (!create)      return (null);    ...    session = manager.createSession();     if (session != null)       return (session.getSession());     else       return (null); }

默认情况下,manager把它的session对象存储在内存中。但是,Tomcat也可以允许manager把它的session对象持久化到存储文件或数据库中。Catalina提供org.apache.catalina.session包,这个包中包含了session对象相关的类型和session管理。

这章分三部分:"Sessions", "Managers"和"Stores"。

Sessions

在servlet编程中,一个session对象由javax.servlet.http.HttpSession接口表示。这个接口的实现是org.apache.catalina.session包下的StandardSession类。但是,出于安全考虑,manager不会传递一个StandardSession实例给一个servlet。它使用在org.apache.catalina.session包下面的facade类:StandardSessionFacade。在内部,管理器与另外一个facade:org.apache.catalina.Session一起工作。类图:



The Session Interface

Session接口作为一个Catalina内部的fa?ade。Session接口的标准实现是StandardSession。
StandardSession也实现了javax.servlet.http.HttpSession接口。
Listing 9.1: The Session interface    package org.apache.catalina; import java.io.IOException; import java.security.Principal; import java.util.Iterator; import javax.servlet.ServletException; import javax.servlet.http.HttpSession;  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); } 

Session对象总是被包含在一个manager里面的。setManager和getManager方法用来把一个Session实例和一个manager相关联起来。一个Session实例也有一个唯一的标识符。可以使用setId和getId方法来访问Session的标识符。manager调用getLastAccessedTime方法来确定一个Session对象是否合法有效。manager调用setValid和reset方法来设置和重新设置一个session对象为合法有效。每次一个Session实例被访问,它的access方法被调用来修改它的最后被访问时间(last accessed time)。最后,manager可以调用它的expire方法把一个session设为超时。getSession方法返回一个被这个facade包装后的HttpSession对象。

The StandardSession Class

StandardSession类是Session接口的标准实现。它除了实现了javax.servlet.http.HttpSession 和org.apache.catalina.Session,还实现了java.lang.Serializable让Session对象可以被序列化。

这个类的构造函数接收一个Manager实例,使一个Session对象总是有一个对应的Manager。
public StandardSession(Manager manager);

下面是一些重要的private变量。注意transient关键字修饰的变量不会被序列化。
// session attributes private HashMap attributes = new HashMap(); // the authentication type used to authenticate our cached Principal, private transient String authType = null; private long creationTime = 0L; private transient boolean expiring = false; private transient StandardSessionFacade facade = null; private String id = null; private long lastAccessedTime = creationTime; // The session event listeners for this Session. private transient ArrayList listeners = new ArrayList(); private Manager manager = null; private int maxInactiveInterval = -1; // Flag indicating whether this session is new or not. private boolean isNew = false; private boolean isValid = false; private long thisAccessedTime = creationTime;

注意在Tomcat 5中,上面的变量是protected修饰的。每个变量都有一对get/set方法。

getSession方法通过传递这个实例来创建一个StandardSessionFacade对象。
public HttpSession getSession() {    if (facade == null)      facade = new StandardSessionFacade(this);    return (facade); }

一个Session对象在一段时间内(超过了Manager里的maxInactiveInterval变量的值)没有被访问。它将被设置为超时过期。让一个Session对象超时过期,调用Session接口的expire方法。
Listing 9.2: The expire method    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, "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();    } }

超时处理包括了设置一个叫做expiring的内部变量、从Manager中移除Session实例和触发一些事件。

The StandardSessionFacade Class

要把一个Session对象传递给servlet,Catalina要实例化StandardSession类,填充属性,然后把它传递给servlet。它传递给一个StandardSessionFacade实例,只提供了在javax.servlet.http.HttpSession的方法实现。这样,servlet程序员就不能把HttpSession对象向下转型成StandardSessionFacade类,访问它的public方法。

Manager

manager管理是session对象的。例如:它创建session对象和让session对象失效。manager是由org.apache.catalina.Manager接口表示的。在Catalina中,org.apache.catalina.session包中包含了ManagerBase类,它提供了通用的功能的实现。ManagerBase有两个直接的子类:StandardManager和PersistentManagerBase。

当应用程序运行是时,StandardManager把session对象存储在内存中。当应用程序停止了,它把就当前在内存中所有的session对象存储到一个文件中去。当再次启动应用程序时,在从文件中把session对象加载进内存。

PersistentManagerBase类是manager组件的基类,它把session对象存储到辅助存储器里面。它有两个子类:PersistentManager和DistributedManager—istributedManager只在Tomcat 4中),类图:



The Manager Interface

Manager接口代表了一个Manager组件:
Listing 9.3: The Manager interface    package org.apache.catalina; import java.beans.PropertyChangeListener; import java.io.IOException;  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 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; } 

首先,Manager接口用getContainer 和setContainer方法把Manager的实现和一个context相关联起来。createSession方法创建一个Session对象。add方法把一个Session实例添加到session池中。remove方法把Session对象从session池中移除。getMaxInactiveInterval和setMaxInactiveInterval方法返回和指定Manager将要等待用户拥有一个与该用户相关联的session的指定秒数。超过这个时间秒数,Manager将销毁这个session,即该session失效了。

最后,在Manager实现里支持一种持久化机制。load和unload方法支持把session持久化存储到辅助存储器。通过这个Manager实现,unload方法把当前活动的session存储到指定的存储地方。load方法把已被持久化的session重新加载到内存中去。

读书人网 >软件架构设计

热点推荐