论坛首页 Java企业应用论坛

《How Tomcat Works》翻译(9) 之 会话管理

浏览 3454 次
精华帖 (2) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-12-08   最后修改:2010-12-19

 

第九章、会话管理

一、前言部分

 

Catalina通过一个叫做manager的组件来支持会话管理,它是由org.apache.catalina.Manager接口代表。A manager一直与context相关联,还有就是manager负责创建、更新、销毁会话对象同时也会返回任何组件所需要的有效的会话对象。

 

一个servlet通过调用javax.servlet.http.HttpServletRequest接口中的getSession方法获得一个session对象,该接口是在默认连接器里由org.apache.catalina.connector.HttpRequestBase类实现的。这里在HttpRequestBase类中有一些相关的方法。

 

 

 

  public HttpSession getSession() {

        return (getSession(true));

    }
 public HttpSession getSession(boolean create) {
        if( System.getSecurityManager() != null ) {
            PrivilegedGetSession dp = new PrivilegedGetSession(create);
            return (HttpSession)AccessController.doPrivileged(dp);
        }
        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);
        if ((context != null) && (response != null) &&
            context.getCookies() &&
            response.getResponse().isCommitted()) {
            throw new IllegalStateException
              (sm.getString("httpRequestBase.createCommitted"));
        }

        session = manager.createSession();
        if (session != null)
            return (session.getSession());
        else
            return (null);

    }

 

默认下,一个manager把所有的sessions对象存储在内存中。然而,Tomcat也允许一个manager把会话对象存放在文件只能够或者数据库(通过JDBC)。Catalina提供了org.apache.catalina.session包,里面包含了会话对象和会话管理类型。

 

这章从三个部分解释在Catalina中的会话管理:"Session", " Managers ",  " Stores ".最后部分就用Context关联manager来解释这个应用程序。

 

二、会话

 

在servlet程序设计中,一个会话对象由javax.servlet.http.HttpSession接口代表,此接口实现的类是StandardSession(在org.apache.catalina.session包中)。然而,对于安全考虑,manager不会传给一个StandardSession实例给servlet,相反它把自己封装了一次,该类的名字是StandardSessionFacade(在org.apache.catalina.session包中)。注解:看到没有又用来了门面模式啦。。。。 。实际上,manager与另外一个门面(org.apache.catalina.Session接口)协调工作。下面的UML图是关于会话相关的类型。注意为了使图精简我就把org.apache.catalina的前缀(Session, StandardSession,StandardSessionFacade)去掉.

 


三、The Session 接口

 

The Session 接口充当了Catalina内部门面角色。the Session接口的标准实现是StandardSession类,同时它也实现了javax.servlet.http.HttpSession接口,The Session接口下面的代码:

package org.apache.catalina;


import java.security.Principal;
import java.util.Iterator;
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);


}
 

一个会话对象一直包含在一个manager中,the setManager和getManager方法目的是一个会话实例与一个manager相关联. 一个会话实例同时也有一个唯一的标志符( 通过The Context相关联的manager),Session标识符也能够被the setId和getId方法访问。the manager决定一个会话对象的有效性来调用The getLastAccessedTime方法,The manager调用了setValid方法是设置或者是重新设置一个会话对象的有效性。只要每次会话实例被访问,那么其方法就会被调用最近更新时间。最后,The manager能够使得一个会话对象过期,通过调用the expire方法; the getSession方法返回一个门面封装了的HttpSession对象。

 

四、The StandardSession类

 

The StandardSession类是实现The Session接口的标准实现。除此之外他还实现了javax.servlet.http.HttpSession接口和java.lang.Serializable(这个是为了使得会话对象能够序列化)接口。

 

The standardSession的构造函数接收一个Manager实例,目的是使得一个会话对象一直拥有一个Manager.

 

     public StandardSession(Manager manager);

 

下面有一些重要的私有变量来维护状态, 注意the transient关键字是让这些变量不能序列化。

 



 注意:在Tomcat5中以上的变量时保护的,而在Tomcat 4 中是私有变量。每个变量都有get/set 方法。

 

The getSession方法通过传this实例创建一个StandardSessionFacade对象:

 

  public HttpSession getSession(){

       if(facade == null)

                        facade=new StandardSessionFacade(this);

            return facade;

  }

 

在Manager中如果一个会话对象没有访问的这个时间段超出了the maxInactiveInternal变量的值那么此会话就过期。能使一个会话对象过期,是通过调用了The Session接口的expire方法。下面就给出在Tomcat 4中,在StanardSession类实现了这个接口的方法:

 

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();
        }

    }
 

 

 

 

该方法的处理过程包括:设置内部变量,从Manager中移除The Session实例,触发一些事件。

 

五、The StandardSessionFacade类

 

为了传一个session对象给Servlet,Catalina实例化The StandardSession类并封装这个实例,在把它传给Servlet.  然而,传给Servlet的是一个StandardSessionFacade实例( 该类仅仅实现了javax.servlet.http.HttpSession接口 ),那为什么要这么做呢?答案是:为了让servlet程序设计者编程时,无法让HttpSession对象向上转型为StandardSession,这是因为仅仅让程序设计者访问公共的方法,而一些私有的方法不暴露给程序设计者。

 

六、Manager

 

一个Manager管理会话对象,例如:它能创建会话对象,也能销毁会话对象。一个Manager由org.apache.catalina.Manager接口代表。在Catalina中,the org.apache.catalina.session包中,包含了ManagerBase类(它实现了公有的功能)。The ManagerBase有两个直接的子类:StandardManager和PersistentManagerBase.

 

当容器运行时,The StandardManager在内存中存储会话对象。然而,如果停止,那么StandardManager把当前内存中所有的会话对象存储在一个文件中,当又重新启动时,又会重新加载这些会话对象。

 

PersistentManagerBase是manager的一个基本组件(它在二级存储中存储了会话对象),该类也有两个子类: PersistentManager和DistributedManager(给类仅仅在Tomcat 4中能够使用)。下面是UML类图,关于The Manager接口和其实现的类:

 


七、The Manager 接口

 

The Manager接口代表了一个Manager组件,下面是其接口的方法:

 

package org.apache.catalina;


import java.beans.PropertyChangeListener;
import java.io.IOException;
public interface Manager {
    public Container getContainer();


    /**
     * Set the Container with which this Manager is associated.
     *
     * @param container The newly associated Container
     */
    public void setContainer(Container container);


    /**
     * Return the DefaultContext with which this Manager is associated.
     */
    public DefaultContext getDefaultContext();


    /**
     * Set the DefaultContext with which this Manager is associated.
     *
     * @param defaultContext The newly associated DefaultContext
     */
    public void setDefaultContext(DefaultContext defaultContext);



    /**
     * Return the distributable flag for the sessions supported by
     * this Manager.
     */
    public boolean getDistributable();


    /**
     * Set the distributable flag for the sessions supported by this
     * Manager.  If this flag is set, all user data objects added to
     * sessions associated with this manager must implement Serializable.
     *
     * @param distributable The new distributable flag
     */
    public void setDistributable(boolean distributable);


    /**
     * Return descriptive information about this Manager implementation and
     * the corresponding version number, in the format
     * <code>&lt;description&gt;/&lt;version&gt;</code>.
     */
    public String getInfo();


    /**
     * Return the default maximum inactive interval (in seconds)
     * for Sessions created by this Manager.
     */
    public int getMaxInactiveInterval();


    /**
     * Set the default maximum inactive interval (in seconds)
     * for Sessions created by this Manager.
     *
     * @param interval The new default value
     */
    public void setMaxInactiveInterval(int interval);


    // --------------------------------------------------------- Public Methods


    /**
     * Add this Session to the set of active Sessions for this Manager.
     *
     * @param session Session to be added
     */
    public void add(Session session);


    /**
     * Add a property change listener to this component.
     *
     * @param listener The listener to add
     */
    public void addPropertyChangeListener(PropertyChangeListener listener);


    /**
     * Construct and return a new session object, based on the default
     * settings specified by this Manager's properties.  The session
     * id will be assigned by this method, and available via the getId()
     * method of the returned session.  If a new session cannot be created
     * for any reason, return <code>null</code>.
     *
     * @exception IllegalStateException if a new session cannot be
     *  instantiated for any reason
     */
    public Session createSession();


    /**
     * Return the active Session, associated with this Manager, with the
     * specified session id (if any); otherwise return <code>null</code>.
     *
     * @param id The session id for the session to be returned
     *
     * @exception IllegalStateException if a new session cannot be
     *  instantiated for any reason
     * @exception IOException if an input/output error occurs while
     *  processing this request
     */
    public Session findSession(String id) throws IOException;


    /**
     * Return the set of active Sessions associated with this Manager.
     * If this Manager has no active Sessions, a zero-length array is returned.
     */
    public Session[] findSessions();


    /**
     * Load any currently active sessions that were previously unloaded
     * to the appropriate persistence mechanism, if any.  If persistence is not
     * supported, this method returns without doing anything.
     *
     * @exception ClassNotFoundException if a serialized class cannot be
     *  found during the reload
     * @exception IOException if an input/output error occurs
     */
    public void load() throws ClassNotFoundException, IOException;


    /**
     * Remove this Session from the active Sessions for this Manager.
     *
     * @param session Session to be removed
     */
    public void remove(Session session);


    /**
     * Remove a property change listener from this component.
     *
     * @param listener The listener to remove
     */
    public void removePropertyChangeListener(PropertyChangeListener listener);

    public void unload() throws IOException;

}
 

首先,The Manager接口有getContainer和setContainer方法目的是一个实现Manager接口类与一个Context相关联。The CreateSession方法就是创建一个会话对象。The add方法把会话实例添加到会花池中,The remove方法是把会话对象从会话池中移除掉。The getMaxInactiveInternal和setMaxInactiveInternal方法返回(and specifices the number of sends the Manager will wait for the user associated with a session to  come back before destorying the session).这里不会翻译。。。悲剧。。。

 

最后,the load和upload方法支持把可持续化的会话存储在第二个存储空间中(这个是有PersistManager中支持可持续化类型机制),The upload方法保存了当前激活的会话对象(也就是第一存储空间中该类时standardManger),并且the Load方法也支持把存储在第二存储空间的会话对象引入到内存中。

 

八、The ManagerBase类

 

The ManagerBase类是一个抽象类( 它的父类是Manager类 )。这个类为它的孩子提供公共的功能,此外,ManagerBase有一个createSession方法创建一个会话对象。每个session有一个唯一的标志符,这个标识符是由保护方法generateSessionId方法返回。

 

注意:一个激活的session是一个有效的会话对象,而没有过期。

 

一个特定的context下的Manager的实例管理整个激活的session. 这些激活的session存储在一个叫sessions的HashMap中:

                 protected HashMap sessions= new HashMap();

The add方法把一个session对象添加到sessions  HashMap中,这个方法请看下面的代码:

 

     public void add(Session session){

 

           synchronized(sessions){

                   sessions.put(session.getId(),session);

 

                }

}

 

The remove方法从HashMap中移除一个会话对象,下面是其方法代码:

 

           public void remove(Session session){

 

                 synchronized(sessions){

                      sessions.remove(session.getId());

 

                  }

  }

 

 The findSession没有参数的方法,是返回全部激活的会话( 来自存放在HashMap中的全部激活的session,他转换成数组

 )。The findSession有参数的方法(session标志符作为参数),它返回一个该标志符对应的一个会话实例。这些重载的方法请看下面代码:

 

 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);
        }

    }
 

 

九、StandardManager

 

The StandardManager类是Manager接口的一个标准实现,在内存中存储了整个会话对象,它也同时实现了The Lifecycle接口(请看在第六章、Lifecycle),这样就可以用start和stop来控制组件。实现stop方法中调用了upload方法(就是序列化有效的session实例到文件中,文件名字叫做SESSIONS.ser)。The SESSIONS.ser文件能够在CATALINA_HOME目录下找到。比如,在Tomcat 4和 Tomcat 5 中,如果 你运行本应用程序的代码,你就会发现在CATALINA_HOME/work/Standalone/localhost/examples目录下能找到SESSIONS.ser文件。当StandardManager有重新启动时,这些会话对象通过调用the Load方法全部读到内存中。

 

 A Manager也负责销毁不再有效的会话对象。在Tomcat 4 中的StandardManager中,这样的实现,它是用了一个专门的线程来实现销毁会话对象。由于这个原因,StandardManager实现了 java.lang.Runnable, 请看下面实现run的方法:

 

 

  public void run() {

        // Loop until the termination semaphore is set
        while (!threadDone) {
            threadSleep();
            processExpires();
        }

    }

 

The threadSleep方法调用了threadSleep(里面主要是Thread.sleep(checkInterval * 1000L)),the checkInterval变量是以秒为单位,默认值是60秒,也可以通过调用setCheckInterval方法改变这个值。

 

  The processExpire方法: 循环遍历由StandardManager管理的整个会话对象,每个Session对象实例把lastAccessedTime变量与当前时间相比较。如果当前时间减去 lastAccessedTime的值大于 maxInactiveInternal,那么该方法就会调用The session接口中的expire方法使得会话该对象过期。The maxInactiveInternal的值通过调用setMaxInactiveInternal方法来改变这个值。在StandardManager中的maxInactiveInternal变量默认值是 60. 呵呵呵。。不要愚蠢的认为maxInactiveInternal值是在Tomcat部署的时候设置的。同时,The setContainer方法:它调用了the org.apache.catalina.core.ContainerBase类中的setManager方法(你一直都要调用setManager方法目的是context和Manager相关联),来重写这个值。下面是setContainer方法中的一些代码:

 

       setMaxInactiveInternal((( Context ) this.container ).getSessionTimout() * 60 );

 

 注意:the sessionTimeOut变量的默认值在org.apache.catalina.core.StandardContext类是30秒。在Tomcat 5中,The StandradManager类没有实现 java.lang.Runnable接口。在Tomcat 5 中的StandardManager对象中的The processExpires方法直接调用了the backgroundprocess方法,但是Tomcat 4不是这样做的。

 

      public  void   backgroundProcess(){

               processExpires();

           }

 

 在 StandardManager中的backgroundProcess方法是通过the org.apache.catalina.core.StandardContext实例(the Container和manager相关联)被调用的。StandardContext周期的调用了backgroundProcess方法这个将会在第十二章进行讨论。

 

 

 

十、PersistentManagerBase

 

 The PersistentManagerBase类是整个可持久化管理的父类。StandardManager和 persistent manager主要的区别就是后者存在一个store,一个 store代表可管理session对象的第二级存储,The PersistentManagerBase类使用了一个私有引用对象(叫做store).

 

            private Store store=null;

 

在一个可持久化管理中,整个session对象既能备份有能迁移。当一个会话对象备份时,The session 对象就会拷贝到一个store中,原始的那个还是会继续停留在内存中。因此,如果服务器崩溃了,激活的会话对象能够在the store中恢复过来。当一个session对象被迁移时,它就会被迁移到the store中,那为什么要这么做呢?这是因为,激活的会话对象的数目已经超出了一个特定的值或者The session对象已经停留在内存中太久并且从来没有用到过它。迁移的目的就是保存内存中的会话对象。注意激活的对象就是停留在内存中的对象。

 

 在Tomcat 4 中PersistentManagerBase类实现了java.lang.Runnable接口,目的是使用一个独立的线程周期的备份和迁移激活的会话对象,下面是实现run方法的代码:

 

 

 

 

  • 大小: 81.7 KB
  • 大小: 81.6 KB
  • 大小: 147.6 KB
   发表时间:2010-12-17  
he_wen 写道

 

第九章、会话管理

一、前言部分

 

Catalina通过一个叫做manager的组件来支持会话管理,它是由org.apache.catalina.Manager接口代表。A manager一直与context相关联,还有就是manager负责创建、更新、销毁会话对象同时也会返回任何组件所需要的有效的会话对象。

 

一个servlet通过调用javax.servlet.http.HttpServletRequest接口中的getSession方法获得一个session对象,该接口是在默认连接器里由org.apache.catalina.connector.HttpRequestBase类实现的。这里在HttpRequestBase类中有一些相关的方法。

 

 

 

  public HttpSession getSession() {

        return (getSession(true));

    }
 public HttpSession getSession(boolean create) {
        if( System.getSecurityManager() != null ) {
            PrivilegedGetSession dp = new PrivilegedGetSession(create);
            return (HttpSession)AccessController.doPrivileged(dp);
        }
        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);
        if ((context != null) && (response != null) &&
            context.getCookies() &&
            response.getResponse().isCommitted()) {
            throw new IllegalStateException
              (sm.getString("httpRequestBase.createCommitted"));
        }

        session = manager.createSession();
        if (session != null)
            return (session.getSession());
        else
            return (null);

    }

 

默认下,一个manager把所有的sessions对象存储在内存中。然而,Tomcat也允许一个manager把会话对象存放在文件只能够或者数据库(通过JDBC)。Catalina提供了org.apache.catalina.session包,里面包含了会话对象和会话管理类型。

 

这章从三个部分解释在Catalina中的会话管理:"Session", " Managers ",  " Stores ".最后部分就用Context关联manager来解释这个应用程序。

 

二、会话

 

在servlet程序设计中,一个会话对象由javax.servlet.http.HttpSession接口代表,此接口实现的类是StandardSession(在org.apache.catalina.session包中)。然而,对于安全考虑,manager不会传给一个StandardSession实例给servlet,相反它把自己封装了一次,该类的名字是StandardSessionFacade(在org.apache.catalina.session包中)。注解:看到没有又用来了门面模式啦。。。。 。实际上,manager与另外一个门面(org.apache.catalina.Session接口)协调工作。下面的UML图是关于会话相关的类型。注意为了使图精简我就把org.apache.catalina的前缀(Session, StandardSession,StandardSessionFacade)去掉.

 


三、The Session 接口

 

The Session 接口充当了Catalina内部门面角色。the Session接口的标准实现是StandardSession类,同时它也实现了javax.servlet.http.HttpSession接口,The Session接口下面的代码:

package org.apache.catalina;


import java.security.Principal;
import java.util.Iterator;
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);


}
 

一个会话对象一直包含在一个manager中,the setManager和getManager方法目的是一个会话实例与一个manager相关联. 一个会话实例同时也有一个唯一的标志符( 通过The Context相关联的manager),Session标识符也能够被the setId和getId方法访问。the manager决定一个会话对象的有效性来调用The getLastAccessedTime方法,The manager调用了setValid方法是设置或者是重新设置一个会话对象的有效性。只要每次会话实例被访问,那么其方法就会被调用最近更新时间。最后,The manager能够使得一个会话对象过期,通过调用the expire方法; the getSession方法返回一个门面封装了的HttpSession对象。

 

四、The StandardSession类

 

The StandardSession类是实现The Session接口的标准实现。除此之外他还实现了javax.servlet.http.HttpSession接口和java.lang.Serializable(这个是为了使得会话对象能够序列化)接口。

 

The standardSession的构造函数接收一个Manager实例,目的是使得一个会话对象一直拥有一个Manager.

 

     public StandardSession(Manager manager);

 

下面有一些重要的私有变量来维护状态, 注意the transient关键字是让这些变量不能序列化。

 



 注意:在Tomcat5中以上的变量时保护的,而在Tomcat 4 中是私有变量。每个变量都有get/set 方法。

 

The getSession方法通过传this实例创建一个StandardSessionFacade对象:

 

  public HttpSession getSession(){

       if(facade == null)

                        facade=new StandardSessionFacade(this);

            return facade;

  }

 

在Manager中如果一个会话对象没有访问的这个时间段超出了the maxInactiveInternal变量的值那么此会话就过期。能使一个会话对象过期,是通过调用了The Session接口的expire方法。下面就给出在Tomcat 4中,在StanardSession类实现了这个接口的方法:

 

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();
        }

    }
 

 

 

 

该方法的处理过程包括:设置内部变量,从Manager中移除The Session实例,触发一些事件。

 

五、The StandardSessionFacade类

 

为了传一个session对象给Servlet,Catalina实例化The StandardSession类并封装这个实例,在把它传给Servlet.  然而,传给Servlet的是一个StandardSessionFacade实例( 该类仅仅实现了javax.servlet.http.HttpSession接口 ),那为什么要这么做呢?答案是:为了让servlet程序设计者编程时,无法让HttpSession对象向上转型为StandardSession,这是因为仅仅让程序设计者访问公共的方法,而一些私有的方法不暴露给程序设计者。

 

六、Manager

 

一个Manager管理会话对象,例如:它能创建会话对象,也能销毁会话对象。一个Manager由org.apache.catalina.Manager接口代表。在Catalina中,the org.apache.catalina.session包中,包含了ManagerBase类(它实现了公有的功能)。The ManagerBase有两个直接的子类:StandardManager和PersistentManagerBase.

 

当容器运行时,The StandardManager在内存中存储会话对象。然而,如果停止,那么StandardManager把当前内存中所有的会话对象存储在一个文件中,当又重新启动时,又会重新加载这些会话对象。

 

PersistentManagerBase是manager的一个基本组件(它在二级存储中存储了会话对象),该类也有两个子类: PersistentManager和DistributedManager(给类仅仅在Tomcat 4中能够使用)。下面是UML类图,关于The Manager接口和其实现的类:

 


七、The Manager 接口

 

The Manager接口代表了一个Manager组件,下面是其接口的方法:

 

package org.apache.catalina;


import java.beans.PropertyChangeListener;
import java.io.IOException;
public interface Manager {
    public Container getContainer();


    /**
     * Set the Container with which this Manager is associated.
     *
     * @param container The newly associated Container
     */
    public void setContainer(Container container);


    /**
     * Return the DefaultContext with which this Manager is associated.
     */
    public DefaultContext getDefaultContext();


    /**
     * Set the DefaultContext with which this Manager is associated.
     *
     * @param defaultContext The newly associated DefaultContext
     */
    public void setDefaultContext(DefaultContext defaultContext);



    /**
     * Return the distributable flag for the sessions supported by
     * this Manager.
     */
    public boolean getDistributable();


    /**
     * Set the distributable flag for the sessions supported by this
     * Manager.  If this flag is set, all user data objects added to
     * sessions associated with this manager must implement Serializable.
     *
     * @param distributable The new distributable flag
     */
    public void setDistributable(boolean distributable);


    /**
     * Return descriptive information about this Manager implementation and
     * the corresponding version number, in the format
     * <code>&lt;description&gt;/&lt;version&gt;</code>.
     */
    public String getInfo();


    /**
     * Return the default maximum inactive interval (in seconds)
     * for Sessions created by this Manager.
     */
    public int getMaxInactiveInterval();


    /**
     * Set the default maximum inactive interval (in seconds)
     * for Sessions created by this Manager.
     *
     * @param interval The new default value
     */
    public void setMaxInactiveInterval(int interval);


    // --------------------------------------------------------- Public Methods


    /**
     * Add this Session to the set of active Sessions for this Manager.
     *
     * @param session Session to be added
     */
    public void add(Session session);


    /**
     * Add a property change listener to this component.
     *
     * @param listener The listener to add
     */
    public void addPropertyChangeListener(PropertyChangeListener listener);


    /**
     * Construct and return a new session object, based on the default
     * settings specified by this Manager's properties.  The session
     * id will be assigned by this method, and available via the getId()
     * method of the returned session.  If a new session cannot be created
     * for any reason, return <code>null</code>.
     *
     * @exception IllegalStateException if a new session cannot be
     *  instantiated for any reason
     */
    public Session createSession();


    /**
     * Return the active Session, associated with this Manager, with the
     * specified session id (if any); otherwise return <code>null</code>.
     *
     * @param id The session id for the session to be returned
     *
     * @exception IllegalStateException if a new session cannot be
     *  instantiated for any reason
     * @exception IOException if an input/output error occurs while
     *  processing this request
     */
    public Session findSession(String id) throws IOException;


    /**
     * Return the set of active Sessions associated with this Manager.
     * If this Manager has no active Sessions, a zero-length array is returned.
     */
    public Session[] findSessions();


    /**
     * Load any currently active sessions that were previously unloaded
     * to the appropriate persistence mechanism, if any.  If persistence is not
     * supported, this method returns without doing anything.
     *
     * @exception ClassNotFoundException if a serialized class cannot be
     *  found during the reload
     * @exception IOException if an input/output error occurs
     */
    public void load() throws ClassNotFoundException, IOException;


    /**
     * Remove this Session from the active Sessions for this Manager.
     *
     * @param session Session to be removed
     */
    public void remove(Session session);


    /**
     * Remove a property change listener from this component.
     *
     * @param listener The listener to remove
     */
    public void removePropertyChangeListener(PropertyChangeListener listener);

    public void unload() throws IOException;

}
 

首先,The Manager接口有getContainer和setContainer方法目的是一个实现Manager接口类与一个Context相关联。The CreateSession方法就是创建一个会话对象。The add方法把会话实例添加到会花池中,The remove方法是把会话对象从会话池中移除掉。The getMaxInactiveInternal和setMaxInactiveInternal方法返回(and specifices the number of sends the Manager will wait for the user associated with a session to  come back before destorying the session).这里不会翻译。。。悲剧。。。

 

最后,the load和upload方法支持把可持续化的会话存储在第二个存储空间中(这个是有PersistManager中支持可持续化类型机制),The upload方法保存了当前激活的会话对象(也就是第一存储空间中该类时standardManger),并且the Load方法也支持把存储在第二存储空间的会话对象引入到内存中。

 

八、The ManagerBase类

 

 

 

 

 

 

 

0 请登录后投票
   发表时间:2010-12-18   最后修改:2010-12-18
Good job...
最好用 DOCBOOK 组织一下,以便将来发布集中的文档。
我有一个DOCBOOK工具相关的项目,
http://hantsy-labs.googlecode.com
以前我翻译了 Spring Live全书,http://blog.chinaunix.net/u/1096/showart_88617.html
我的博客 http://hantsy.cublog.cn

贵在坚持。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics