《How Tomcat Works》通译(4)之 生命周期

《How Tomcat Works》翻译(4)之 生命周期

第六章 生命周期

一、本章总括

Catalina 由许多组件组成。当Catalina启动后,这些组件同时也需要启动。当Catalina停止,这些组件一定要有机会做一些清楚的工作。比如,当The Container停止后,就必须要底啊用整个加载的Servlet的destory方法以及会话管理一定需要保存到第二存储器的会话对象。启动和关闭组件的一致的原理就是需要实现the org.apache.catalina.Lifecycle接口。

 

实现 the Lifecycle接口的组件也要触发一个或者下面许多事件:BEFORE_STATRT_EVENT,START_EVENT,AFTER_START_EVENT,BEFORE_STOP_EVENT,STOP_EVENT,AFTER_STOP_EVENT.

 当组件开始启动就会触发前面三个事件,当组件关闭时就会触发后面的三个事件。一个事件由the org.apache.catalina,LifecycleEvent类代表。当然如果Catalina组件触发了这些事件,你一定要有一个事件监听器(目的是回应这些事件)。一个Listener有the org.apache.catalina.LifecycleListener接口代表。

 

   这章主要讨论三个类型:Lifecycle,LifecycleEvent,LifecycleListener.除此之外,我们也解释了一个十分有用的类叫做LifecycleSupport(它提供了触发lifecycle事件的一种简易方式并且还处理lifecycle监听)。在这章中,你将要构建一个实现Lifecycle接口类的项目。本章的应用程序是基于第五章应用程序进行扩展。

 

 二、The Lifecycle接口

   Catalina设计者允许一个组件又可以包含其他组件。比如:一个容器能够包含诸如此类的组件:a Loader,a Manager等得。一个父容器负责启动和关闭孩子组件,The catalina设计者把整个组件运用这样的方式,且把组件放到父亲组件中,以至于一个启动类只需要仅仅启动一个单个的组件。因此使用了the Lifecycle接口让一个单一的启动、关闭模式实现成为了可能。现在让我们来看看The Lifecycle接口:

 

package org.apache.catalina;
public interface Lifecycle {
    public static final String START_EVENT = "start";
    public static final String BEFORE_START_EVENT = "before_start";


    /**
     * The LifecycleEvent type for the "component after start" event.
     */
    public static final String AFTER_START_EVENT = "after_start";
    public static final String STOP_EVENT = "stop";
    public static final String BEFORE_STOP_EVENT = "before_stop";
    public static final String AFTER_STOP_EVENT = "after_stop";
    public void addLifecycleListener(LifecycleListener listener);
    public LifecycleListener[] findLifecycleListeners();
    public void removeLifecycleListener(LifecycleListener listener);
    public void start() throws LifecycleException;

    public void stop() throws LifecycleException;


}

 在Lifecycle接口十分重要的方法是the start和stop方法,一个组件提供了实现此接口的所有方法,目的就是该组件的父组件能够关闭和启动该组件。此接口的其他三个方法是addLifecycleListener,findLifecycleListeners,removeLifecycleListener是与listeners相关联的。一个组件能够监听到发生在该组件感兴趣的事件。当一个事件发生就这监听感兴趣的那个事件就被通知。The Lifecycle实例被触发的六个事件的名字以static final String方式定义在Lifecycle接口里面。

 

三、The LifecycleEvent类

  The org.apache.catalina.LifecycleEvent类代表了a lifecycle事件,下面是其呈现的代码:

 

package org.apache.catalina;


import java.util.EventObject;
public final class LifecycleEvent
    extends EventObject {
    public LifecycleEvent(Lifecycle lifecycle, String type) {

        this(lifecycle, type, null);

    }
    public LifecycleEvent(Lifecycle lifecycle, String type, Object data) {

        super(lifecycle);
        this.lifecycle = lifecycle;
        this.type = type;
        this.data = data;

    }
    private Object data = null;
    private Lifecycle lifecycle = null;
    private String type = null;
    public Object getData() {

        return (this.data);

    }
    public Lifecycle getLifecycle() {

        return (this.lifecycle);

    }
    public String getType() {

        return (this.type);

    }


}
 

 四、The LifecycleListener接口

 The org.apache.catalina.LifecycleListener接口代表了一个lifecycle listener,下面是其呈现的代码:

 

package org.apache.catalina;
public interface LifecycleListener {
    public void lifecycleEvent(LifecycleEvent event);


}

 在这个接口中仅仅只有一个方法lifecycleEvent方法。当触发了感兴趣的监听的事件,这个方法就会被调用。

 

 五、The LifecycleSupport类

 该组件实现了Lifecycle,并且一个监听者注册感兴趣的事件。所以该类也提供了在Lifecycle接口中的三个方法(addLifecycleListener,findLifecycleListeners,removeLifecycleListener).该组件必须把所有的监听者以数组或者ArrayList或者类似对象全部存在里面。Catalina提供了提供了一个十分使用的类,那就是是的组件能够更加容易的处理监听者和触发lifecycle事件,该类的名字叫做org.apache.catalina.util.LifecycleSupport.The LifecycleSupport类看下面的代码:

package org.apache.catalina.util;


import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;
public final class LifecycleSupport {
    public LifecycleSupport(Lifecycle lifecycle) {

        super();
        this.lifecycle = lifecycle;

    }
    private Lifecycle lifecycle = null;
    private LifecycleListener listeners[] = new LifecycleListener[0];
    public void addLifecycleListener(LifecycleListener listener) {

      synchronized (listeners) {
          LifecycleListener results[] =
            new LifecycleListener[listeners.length + 1];
          for (int i = 0; i < listeners.length; i++)
              results[i] = listeners[i];
          results[listeners.length] = listener;
          listeners = results;
      }

    }
    public LifecycleListener[] findLifecycleListeners() {

        return listeners;

    }
    public void fireLifecycleEvent(String type, Object data) {

        LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
        LifecycleListener interested[] = null;
        synchronized (listeners) {
            interested = (LifecycleListener[]) listeners.clone();
        }
        for (int i = 0; i < interested.length; i++)
            interested[i].lifecycleEvent(event);

    }
    public void removeLifecycleListener(LifecycleListener listener) {

        synchronized (listeners) {
            int n = -1;
            for (int i = 0; i < listeners.length; i++) {
                if (listeners[i] == listener) {
                    n = i;
                    break;
                }
            }
            if (n < 0)
                return;
            LifecycleListener results[] =
              new LifecycleListener[listeners.length - 1];
            int j = 0;
            for (int i = 0; i < listeners.length; i++) {
                if (i != n)
                    results[j++] = listeners[i];
            }
            listeners = results;
        }

    }


}

在上面你能够看到,The LifecyleSupport类用一个数组存储了整个lifecycle监听者,并且该数组初始化为了。

     private LifecycleListener listeners[]=new LifecycleListener[0];

 

 当一个listener被添加到了addLifecycleListener方法中,一个新的数组就会创建并且该数组的长度是以原来数组长度加1的。然后,整个原来数组被复制到新建的数组当中以及新的listener也别添加到新的数组中去。注解:这样写代码就是怎样创建动态数组,非常值得借鉴。

 当一个listener通过removeLifecycleListener方法移除,新的数组也会被创建,并且该数组的长度是原来数组长度减1,然而除了那个要删除的元素,原来数组的元素全部都要复制到新的数组中去。注解:推荐大家看看removeLifecycleListener方法中的代码是怎样删除一个元素的,里面的代码十分的优雅,非常值得我们学习。

 

The fireLifecycleEvent 方法是触发一个lifecycle事件。首先,方法里面克隆所有的监听者并存放在一个数组中。然后又调用数组中每个对象的lifecycleEvent方法(触发的事件当做参数传过去)。

 

 实现Lifecycle组件要使用LifecycleSupport类。比如,在这章的应用程序中的The SimpleContext类,就定义了LifecycleSupport为成员变量:

      protected LifecycleSupport lifecycle=new LifecycleSupport(this);

 如果要添加一个lifecycle listener,那么the SimpleContext类就必须要调用The LifecycleSupport类中的addLifecycleListener方法:

 

     public void addLifecycleListener(LifecycleListener listener){

         lifecycle.addLifecycleListener(listener);

}

 

如果要移除一个lifecycle Listener,那么the SimpleContext类必须调用The LifecycleSupport类中的removeLifecycleListener方法:

 

     public void removeLifecycleListener(LifecycleListener listener){

         lifecycle.removeLifecycleListener(listener);

}

 

 如果要触发一个事件,The SimpleCOntext类必须调用the LifecycleSupport类中的 fireLifecycleEvent方法,下面是其代码:

        lifecycle.fireLifecycleEvent(START_EVENT,null);

 

六、应用程序

本章的应用程序是基于第五章的应用程序,目的是要说明the Lifecycle接口的使用以及lifecycle相关的类型。本应用程序包含了一个context,两个wrappers以及a Loader, a mapper.在本应用程序中实现Lifecycle接口的组件和使用在context中的一个listener.为了使本程序尽量简单,这里就没有使用第五章中的两个valves。下面会呈现本应用程序的类图关系。注意的是:这些接口(Container,Wrapper,Context,Loader,Mapper)和这些类(SimpleContextValve,SimpleContextMapper,SimpleWrapperValve)是没有在下面类中体现出来的。


《How Tomcat Works》通译(4)之 生命周期
 注意的是:The SimpleContextLifecycleListener类代表了the SimpleContext类的监听类。The SimpleContextValve,SimpleContextMapper,SimpleWrapperValve类的功能与第五章是一样,这里就不在详细的讨论。

 

六、ex06.pyrmont.core.SimpleContext

 

The SimpleContext类在本应用程序与第五章是十分相似的,除了它实现了The Lifecycle接口。The SimpleContext使用了一个成员变量那就是LifecycleSupport实例。

     protected LifecycleSupport lifecycle=new LifecyleSupport(this);

 

 如果The SimpleContext实例已经启动了,那么The SimpleContext需要一个布尔变量来进行控制是否该类已经启动。下面的代码就是The SimpleContext实现了the Lifecycle接口。

 

 

public void addLifecycleListener(LifecycleListener listener) {
    lifecycle.addLifecycleListener(listener);
  }

  public LifecycleListener[] findLifecycleListeners() {
    return null;
  }

  public void removeLifecycleListener(LifecycleListener listener) {
    lifecycle.removeLifecycleListener(listener);
  }

  public synchronized void start() throws LifecycleException {
    log("starting Context");
    if (started)
      throw new LifecycleException("SimpleContext has already started");

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
    started = true;
    try {
      // Start our subordinate components, if any
      if ((loader != null) && (loader instanceof Lifecycle))
        ((Lifecycle) loader).start();

      // Start our child containers, if any
      Container children[] = findChildren();
      for (int i = 0; i < children.length; i++) {
        if (children[i] instanceof Lifecycle)
          ((Lifecycle) children[i]).start();
      }

      // Start the Valves in our pipeline (including the basic),
      // if any
      if (pipeline instanceof Lifecycle)
        ((Lifecycle) pipeline).start();
      // Notify our interested LifecycleListeners
      lifecycle.fireLifecycleEvent(START_EVENT, null);
    }
    catch (Exception e) {
      e.printStackTrace();
    }

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
    log("Context started");
  }

  public void stop() throws LifecycleException {
    log("stopping Context");
    if (!started)
      throw new LifecycleException("SimpleContext has not been started");
    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
    lifecycle.fireLifecycleEvent(STOP_EVENT, null);
    started = false;
    try {
      // Stop the Valves in our pipeline (including the basic), if any
      if (pipeline instanceof Lifecycle) {
        ((Lifecycle) pipeline).stop();
      }

      // Stop our child containers, if any
      Container children[] = findChildren();
      for (int i = 0; i < children.length; i++) {
        if (children[i] instanceof Lifecycle)
          ((Lifecycle) children[i]).stop();
      }
      if ((loader != null) && (loader instanceof Lifecycle)) {
        ((Lifecycle) loader).stop();
      }
    }
    catch (Exception e) {
      e.printStackTrace();
    }
    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
    log("Context stopped");
  }

 注意the start 方法启动了所有孩子容器与之关联的组件如:The Loader,Pipeline,Mapper, 那么stop方法是怎么停止他们的呢?通过这种机制(开启容器模块中所有的组件),你仅仅需要启动在层次等级上最高那个组件(在本应用程序是The SimpleContext实例)。为了停止他们,你仅仅需要停止一样的单个组件。

 

 在SimpleContext类中的start方法开始是通过核实,如果组件在先前以及启动了,那么就会抛出一个异常LifecycleException.

        if(strated)

                throw new LifecycleException(

                           "SimpleContext has already started");

 

   然后又调用the BEFORE_START_EVENT事件。

 

    lifecycle.fireLifecycleEvent(BEFORE_START_EVENT,null);

 

结果,在SimpleContext实例中注册感兴趣的事件的每个监听者将被通知(也叫调用)。在本应用程序中SimpleContextLifecycleListener是注册感兴趣的事件之一。当我们讨论the SimpleContextLifecycleListener类,我就会看到这个监听者会发生什么样的事情。

 

   接下来,the start 方法设置布尔值started为TRUE,这就表明该组件已经启动了。

       started=true;

the start 方法然后又调用整个组件(该组件的孩子容器)。当前有两个组件(SimpleLoader , SimplePieline)实现了the Lifecycle接口. The SimpkeContext有两个孩子容器即两个Wrappers。这些wrappers中有一个类SimpleWrapper(他也是实现了Lifecycle接口)。

 

try {
      // Start our subordinate components, if any
      if ((loader != null) && (loader instanceof Lifecycle))
        ((Lifecycle) loader).start();

      // Start our child containers, if any
      Container children[] = findChildren();
      for (int i = 0; i < children.length; i++) {
        if (children[i] instanceof Lifecycle)
          ((Lifecycle) children[i]).start();
      }

      // Start the Valves in our pipeline (including the basic),
      // if any
      if (pipeline instanceof Lifecycle)
        ((Lifecycle) pipeline).start();
 

 这些组件和孩子都启动后,这个start方法有开始激发两个事件:START_EVENT, AFTER_START_EVENT.

 

                // Notify our interested LifecycleListeners
      lifecycle.fireLifecycleEvent(START_EVENT, null);

                  ...

                  ...

                  ...

       lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);

 

  The stop方法首先核实这个实例是否已经启动,如果没有启动,那么就会抛出一个LifecycleException异常。

 

     if (!started)
      throw new LifecycleException("SimpleContext has not been started");

然后又产生两个事件:BEFORE_STOP_EVENT,STOP_EVENT,并且重新设置布尔值started。

 

                 // Notify our interested LifecycleListeners
                lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
                lifecycle.fireLifecycleEvent(STOP_EVENT, null);
                started = false;

 接下来,the stop方法停止与容器相关联整个组件以及SimpleContext实例的孩子容器。

 

try {
      // Stop the Valves in our pipeline (including the basic), if any
      if (pipeline instanceof Lifecycle) {
        ((Lifecycle) pipeline).stop();
      }

      // Stop our child containers, if any
      Container children[] = findChildren();
      for (int i = 0; i < children.length; i++) {
        if (children[i] instanceof Lifecycle)
          ((Lifecycle) children[i]).stop();
      }
      if ((loader != null) && (loader instanceof Lifecycle)) {
        ((Lifecycle) loader).stop();
      }
    }
    catch (Exception e) {
      e.printStackTrace();
    }

 最后又触发了AFTER_STOP_EVENT事件

 

          // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);

 

七、ex06.prymont.core.SImpleContextLifecycleListener

   The SimpleContextLifecycleListener类代表了一个SimpleContext实例的监听者,下面的代码:

 

package ex07.pyrmont.core;

import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;

public class SimpleContextLifecycleListener implements LifecycleListener {

  public void lifecycleEvent(LifecycleEvent event) {
    Lifecycle lifecycle = event.getLifecycle();
    System.out.println("SimpleContextLifecycleListener's event " +
      event.getType().toString());
    if (Lifecycle.START_EVENT.equals(event.getType())) {
      System.out.println("Starting context.");
    }
    else if (Lifecycle.STOP_EVENT.equals(event.getType())) {
      System.out.println("Starting context.");
    }
  }
}

 The SimpleContextLifecycleListener类实现了LifeEvent方法是十分简单的。该方法里面的功能打印了调用事件的的类型。如果是一个STRT_EVENT事件,那么The lifecycleEvent方法就是打印这个字符串:Starting context. 如果是一个STOP_EVENT事件那么该方法就会打印这样的字符串:Stopping context.

 

 八、ex06.pyrmont.core.SimpleLoader

 

  The SimpleLoader 类与第五章的类非常相似,除了该类在本应用程序实现了The Lifecycle接口。这个类实现了The Lifecycle接口的这些方法没有做任何事情,除了打印了一个字符串在控制台上。然而,更加重要的是通过实现The Lifecycle接口的SimpleLoader实例开始有容器被关联。(这句话翻译的有问题)

 

  public void addLifecycleListener(LifecycleListener listener) {
  }

  public LifecycleListener[] findLifecycleListeners() {
    return null;
  }

  public void removeLifecycleListener(LifecycleListener listener) {
  }

  public synchronized void start() throws LifecycleException {
    System.out.println("Starting SimpleLoader");
  }

  public void stop() throws LifecycleException {
  }
 

 

八、ex06.pyrmont.core.SimplePipeline

 

The SimplePipeline类除了实现了the Pipeline接口同时还实现了The Lifecycle接口。这个类实现该接口的方法都是空实现,但是此类的实例能够被启动并且它是与容器关联的。其他的功能都与第五章的the SimplePipeline类十分类似。

 

八、ex06.pyrmont.core.SimpleWrapper

 

  这个类与第五章的SimpleWrapper类十分类似,在本应用中它也实现了The Lifecycle接口以至于它能够被父类容器启动。在本应用程序中实现Lifecycle接口的大部分方法都是空实现,除了the start和the stop方法不是。下面是其实现此接口的代码:

 

 public void addLifecycleListener(LifecycleListener listener) {
  }

  public LifecycleListener[] findLifecycleListeners() {
    return null;
  }

  public void removeLifecycleListener(LifecycleListener listener) {
  }

  public synchronized void start() throws LifecycleException {
    System.out.println("Starting Wrapper " + name);
    if (started)
      throw new LifecycleException("Wrapper already started");

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
    started = true;

    // Start our subordinate components, if any
    if ((loader != null) && (loader instanceof Lifecycle))
      ((Lifecycle) loader).start();

    // Start the Valves in our pipeline (including the basic), if any
    if (pipeline instanceof Lifecycle)
      ((Lifecycle) pipeline).start();

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(START_EVENT, null);
    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
  }

  public void stop() throws LifecycleException {
    System.out.println("Stopping wrapper " + name);
    // Shut down our servlet instance (if it has been initialized)
    try {
      instance.destroy();
    }
    catch (Throwable t) {
    }
    instance = null;
    if (!started)
      throw new LifecycleException("Wrapper " + name + " not started");
    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(STOP_EVENT, null);
    started = false;

    // Stop the Valves in our pipeline (including the basic), if any
    if (pipeline instanceof Lifecycle) {
      ((Lifecycle) pipeline).stop();
    }

    // Stop our subordinate components, if any
    if ((loader != null) && (loader instanceof Lifecycle)) {
      ((Lifecycle) loader).stop();
    }

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
  }

 在SimpleWrapper 中的The start方法与在SimpleContext类的start方法十分类似。该类能够启动添加该类实例任何组件(当前应用程序为了简单就没有任何组件添加在里面),并且触发了the BEFORE_START_EVENT, STRAT_EVENT, AFTER_START_EVENT事件。

 

   在SimpleWrapper中的stop方法甚至更加有趣。打印了一个简单的字符串后,该方法就调用了the servlet实例的destory方法。

 System.out.println("Stopping wrapper " + name);
    // Shut down our servlet instance (if it has been initialized)
    try {
      instance.destroy();
    }
    catch (Throwable t) {
    }

 然后,该方法就核实是否the wrapper是否已经启动了。如果没有启动,那么就会抛出LifecycleException异常。

 

      if (!started)
      throw new LifecycleException("Wrapper " + name + " not started");

 

接下来,该方法就触发了BEFORE_STOP_EVENT和STOP_EVENT事件,并且重新设置了布尔值started.

 

 

   lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);

    // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(STOP_EVENT, null);
    started = false;

 在然后,该方法就停止the loader和pipeline组件。在本应用程序中The SimpleWrappe实例是没有loader组件。

             // Stop the Valves in our pipeline (including the basic), if any
    if (pipeline instanceof Lifecycle) {
      ((Lifecycle) pipeline).stop();
    }

    // Stop our subordinate components, if any
    if ((loader != null) && (loader instanceof Lifecycle)) {
      ((Lifecycle) loader).stop();
    }

 最后,该方法就触发了the AFTER_STOP_EVENT事件

     // Notify our interested LifecycleListeners
    lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);

 

 九、运行本程序

   这里具体怎么运行就不作太的解释

 

 

 十、总结

 

  在本章你已经学会了The Lifecycle接口是怎么工作。这个接口定义了the lifecycle给组件,且提供了一种优雅的方式发送事件给其他的组件。除此之外,The Lifecycle接口也尽可能的在Catalina里使用单个start/stop方法来启动所有组件的start和stop方法。

注解:本章是一个典型的观察者模式,特别要关注哪个辅助类LifecycleSupport,这个太典型了不得不佩服设计者的这种思维,实现组件之间的连接。。。。无话可说学习啊。。。。

 

1 楼 longxiaoyan 2010-12-08  
看英文版多好。