读书人

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

发布时间: 2012-09-18 16:21:42 作者: rapoo

《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 看英文版多好。

读书人网 >软件架构设计

热点推荐