第六章 生命周期
一、本章总括
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)是没有在下面类中体现出来的。
注意的是: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,这个太典型了不得不佩服设计者的这种思维,实现组件之间的连接。。。。无话可说学习啊。。。。