mgjj 发表于 2017-2-8 09:04:06

《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;
public void addLifecycleListener(LifecycleListener listener) {
synchronized (listeners) {
LifecycleListener results[] =
new LifecycleListener;
for (int i = 0; i < listeners.length; i++)
results = listeners;
results = 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.lifecycleEvent(event);
}
public void removeLifecycleListener(LifecycleListener listener) {
synchronized (listeners) {
int n = -1;
for (int i = 0; i < listeners.length; i++) {
if (listeners == listener) {
n = i;
break;
}
}
if (n < 0)
return;
LifecycleListener results[] =
new LifecycleListener;
int j = 0;
for (int i = 0; i < listeners.length; i++) {
if (i != n)
results = listeners;
}
listeners = results;
}
}

}
  在上面你能够看到,The LifecyleSupport类用一个数组存储了整个lifecycle监听者,并且该数组初始化为了。
  private LifecycleListener listeners[]=new LifecycleListener;
  当一个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)是没有在下面类中体现出来的。
  


 注意的是: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 instanceof Lifecycle)
((Lifecycle) children).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 instanceof Lifecycle)
((Lifecycle) children).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 instanceof Lifecycle)
((Lifecycle) children).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 instanceof Lifecycle)
((Lifecycle) children).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]
查看完整版本: 《How Tomcat Works》翻译(4)之 生命周期