《How Tomcat Works》通译(9) 之 会话管理续集

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

八、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方法全部读到内存中。

 

 一个manager也负责摧毁一个不在有效的会话对象。在Tomcat 4中的StandardManager,它是使用了一个专一的线程来处理这样的需求。对于这个原因,StandardManager实现了 java.lang.Runnable,在Tomcat 4 中下面就呈现run方法的代码:

 

public void run() {

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

    }

 

The threadSleep方法让此线程睡眠,时间以秒为单位,时间变量时checkInterval,默认的值是60.你可以通过调用setCheckInterval方法来改变该变量的值。

 

The processExpire方法循环的扫描StandardManager管理的整个会话对象,并且每个会话实例的lastAccessedTime变量与当前的时间相比较。如果他们之间的差值超出了maxInactiveInterval变量,然后该方法就会调用Session接口的expire方法使得会话实例过期。The maxInactiveInternal变量通过调用setMaxInactiveInternal方法来改变该变量的值,并且该变量的默认值是60. 请你不要妄自猜想该变量值是在部署tomcat中可以在配置文件中改变的。The setContainer方法:在org.apache.catalina.core.ContainerBase类中调用setManager方法(你要一直调用setManager目的是为了Manager与context进行关联),重新写maxInactiveInternal变量的值,下面有setContainer方法的部分代码:

 

     setMaxInactiveInterval(((Context)

              this.container).getSessionTimeout*60);

 

注意:the sessionTimeOut变量的默认值在org.apache.catalina.core.StandradContext类中是30秒。

 

在Tomcat 5 中,The StandardManager类中没有实现java.lang.Runnable接口。The processExpire方法在Tomcat 5中的StandardManager对象中是直接的调用了backgroundprocess方法,而在Tomcat 4中不是这样处理的。

 

        public void backgroundProcess(){

               processExpires();

   }

 

The backgroundProcess方法在StandardManager中是由org.apache.catalina.core.StandardContext实例中的backgroundProcess方法调用的,The container与manager相关联。StandardContext周期的调用backgroundProcess方法,这个具体的内容将会在第12章详细讨论。

 

 十、PersistentManagerBase

 

The PersistentManagerBase 类是整个persistent managers的父类。StandardManager和persistent Manager两个类主要不一样的是后者存在一个store. a store 表示着管理session对象的辅助存储器,The PersistentManagerBase 类使用了叫做store的私有对象的引用。

 

         private Store store=null;

在可持续管理中,会话对象即能备份又可从内存中交换出去。当一个回话对象在备份时,会话对象就会复制到一个store里面,而原始的会话对象停留在内存中。因此,如果服务器崩溃了,那么激活的回话对象会在store中被找到。 当一个会话对象置换出去时,会话对象也会移动到store中,因为激活的会话对象的数目会超出特定的数目或者会话对象停留在内存中太久(并且没有做任何事).置换的目的就是为了节约内存。

 

在Tomcat4 PersistentManagerBase实现了 java.lang.Runnable 接口,目的就是让一个独立的线程周期的备份和置换激活的会话对象。下面是run 方法的代码:

 

  public void run(){

           // Loop until the termination semaphore is set

         while(!threadDone){

              threadSleep();

              processExpires();

              processPersistenceChecks();

        }

   }

 

The processExpired 方法正如 StandardManager一样,核实过期的会话对象。The processPersistenceChecks方法又调用了三个方法:

 

             public void processPersistenceChecks(){

 

                    processMaxIdleSwaps();

                    processMaxActiveSwaps();

                    processMaxIdleBackups();

        }

在Tomcat 5中PersistentManagerBase没有实现 Runnable接口。备份和置换是由后台的管理线程实现的,它和StandardContext实例相关联 周期的调用。

 

置换和备份在下面的子部分进行讨论。

 

十一、Swap Out

 

The PersistentManagerBase类在置换会话对象时应用了许多的规则。一个会话对象的置换不是因为激活对象已经超出指定的个数,就是因为会话对象在内存中停留太多的时间(并且没有做任何事).

 

在有许多会话对象的场景下,a PersistentManagerBase实例中,只有当激活对象的数目等于maxActiveSession时,它才置换出任何会话对象。(看The ProcessMaxActiveSwaps 方法)

 

在有许多会话对象闲散了很长时间的场景下, The PersistentManagerBase类使用了了两个变量来判断会话对象是否进行置换:minIdleSwap和 maxIdleSwap. 会话对象 如果它的上次访问时间(lastAcessedTime)超出了minIdleSwap和MaxIdleSwap之间,那么他就会进行置换。为了避免频繁的置换会话对象,那么你应该把 maxIdleSwap变量设置成一个负数。( 看The processMaxIdleSwaps 方法)

 

因为激活对象能够进行置换,所以会话对象既能驻留在内存中又能保存在 store中。因此,The findSession(String id)方法:首先是在内存中寻找会话实例,如果没有找到就在store中寻找。下面是在 PersistentManagerBase类实现的代码:

 

       public  Session findSesssion(String  id)  throws IOException {

 

               Session session=super.findSession(id);

                       return session;

                //  not found in memory,see if the Session is in the Store

                  session=swapIn(id);  //swapIn returns an active session in the Store

                 return session;

     }

 

十二、备份

 

 不是所有的激活会话对象都要备份。PersistentManagerBase 实例仅仅是当会话对象闲散的时间超出了maxIdleBackup变量的值,才会进行备份。The processMaxIdleBackeups 方法执行的就是会话对象的备份。

 

十三、 PersistentManager

 

The PersistentManager 类扩展了 PersistentManagerBase 类。这个类除了两个属性外没有什么可以说的。The PersistentManager 类的代码下面给出:

 

public final class PersistentManager extends PersistentManagerBase {


    // ----------------------------------------------------- Instance Variables


    /**
     * The descriptive information about this implementation.
     */
    private static final String info = "PersistentManager/1.0";


    /**
     * The descriptive name of this Manager implementation (for logging).
     */
    protected static String name = "PersistentManager";


    // ------------------------- Properties


    /**
     * 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 (this.info);

    }

    /**
     * Return the descriptive short name of this Manager implementation.
     */
    public String getName() {

        return (name);

    }
 }
 

十四、DistributedManager

 

在Tomcat 4中 提供了DistrubutedManager类,它的父类是PersistentManagerBase,DistributedManager类主要是用在集群环境中(具有两个或者多个节点)。一个节点表示着Tomcat 的部署。在集群的节点中可以存在不同的机器上或者一台机器上。在集群环境中每个节点都有一个 DistributedManager 实例(Manager要支持会话可复制的条件),因此DistributedManager主要的责任就是可复制性。

 

为了可复制性的目的,DistributedManager发送消息给其他的结点 无论会话对象是被创建的或者是摧毁了的。除此之外,一个结点必须能够从另外的结点接受消息。这样的方式下,an Http 请求在集群环境能够得到应用。

 

为了在其他结点的DistributedManager实例中发送和接收消息,Catalina 在org.apache.cataline.cluter 包中提供了许多类。在这么多类中,The CluterSender类主要是发送消息给其他结点,The CluterReceiver类只要是为了在其他结点接收消息。

 

DistrbutedManager中的 createSession 方法主要是创建一个会话对象存储在当前的实例中,使用了 CluterSender实例发送消息给其他结点。The createSession 方法呈现在下面中: