Catalina中有很多组件,像上一章提到的四种容器,载入器,映射器等都是一种组件。每个组件在对外提供服务之前都需要有个启动过程;组件在销毁之前,也需要有个关闭过程;例如servlet容器关闭时,需要调用servlet的destroy方法,session管理器关闭时必须将seesion对象保存到辅助存储器中等。
Catalina为了更好的控制各组件的启动与销毁流程,做了几个生命周期的接口与工具类出来,对所有需要生命周期控制的组件做了个规范,并将启动与销毁的触发点收束到一个顶层组件中,实现统一启动或关闭所有组件。
这个统一控制的实现方式就是,由最顶层组件发号施令,一层一层往下传播,每个组件只控制其子组件的启动与关闭,直到最底层的组件。
相关的接口与类有以下几个,下面一一介绍
org.apache.catalina.Lifecycle
org.apache.catalina.LifecycleEvent
org.apache.catalina.LifecycleListener
org.apache.catalina.util.LifecycleSupport
Lifecycle接口
Catalina中的组件如果想被纳入统一生命周期管理的话,就必须实现Lifecycle接口。
该接口定义了五个方法与六个字符串属性。
最重要的方法是start()与stop()方法,这两个方法必须被实现。
start()方法中需要执行本组件的启动逻辑并调用子组件的start()方法。stop()方法需要执行本组件的关闭逻辑并调用子组件的stop()方法。Catalina的这种设计使得所有子组件都置于其父组件的“监护”之下,这样,Catalina的启动类只需要启动一个组件就可以将全部应用的组件都启动起来。
六个属性则是定义了start与stop过程中的六个阶段的事件
- BEFORE_START_EVENT:组件启动前
- START_EVENT: 组件启动中
- AFTER_START_EVENT: 组件启动后
- BEFORE_STOP_EVENT: 组件关闭前
- STOP_EVENT: 组件关闭中
- AFTER_STOP_EVENT: 组件关闭后
六种事件发生后,需要有专门的事件监听器来处理。Lifecycle接口中其他三个方法则是与事件监听器相关的方法:添加、移除、查询 事件监听器。
public interface Lifecycle {
public static final String START_EVENT = "start";
public static final String BEFORE_START_EVENT = "before_start";
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;
}
LifecycleEvent类
这个类是对Lifecycle中六种事件的封装,组件触发生命周期的事件后,将事件封装成LifecycleEvent对象,然后作为监听器的方法参数去触发监听。其中type字段放的就是Lifecycle中定义的六个事件之一。
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);
}
}
LifecycleListener接口
这是事件监听器的接口。实现了Lifecycle接口的组件,在触发了一个事件后,将事件封装成LifecycleEvent对象,调用监听器的lifecycleEvent,根据不同事件做相应处理。
package org.apache.catalina;
public interface LifecycleListener {
/**
* 让监听器知晓有事件发生了
*/
public void lifecycleEvent(LifecycleEvent event);
}
LifecycleSupport类
此类是一个工具类,负责辅助 实现了Lifecycle的组件 将LifecycleEvent事件通知到所有监听器。
LifecycleSupport类有两个属性:
- lifecycle:关联的 实现了Lifecycle接口的组件
- listeners:lifecycle关联的监听器
addLifecycleListener与removeLifecycleListener两个方法,通过复制监听器数组的方式来新增或移除监听器。
fireLifecycleEvent方法负责将事件封装成LifecycleEvent对象并作为参数,for循环调用所有监听器的lifecycleEvent方法,执行监听处理。
public final class LifecycleSupport {
public LifecycleSupport(Lifecycle lifecycle) {
super();
this.lifecycle = lifecycle;
}
private Lifecycle lifecycle = null;
private LifecycleListener[] listeners = new LifecycleListener[0];
/**
* 为lifecycle组件添加一个事件监听器
*/
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;
// 这里克隆一下listeners数组,我理解克隆的意义 是为了防止在执行listeners的for循环过程中,又被调用了addLifecycleListener来添加一个listener
synchronized (listeners) {
interested = 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;
}
}
}
其他类
本章其他的类基本沿用了第五章的类。不同点是,本章将各个组件类都实现了Lifecycle接口。
SimpleContext最为最顶层的组件,负责“一键启停”所有组件。SimpleContext拥有一个LifecycleSupport属性,用来处理对生命周期事件的监听。本章做了一个SimpleContextLifecycleListener类来作为SimpleContext的事件监听器。在start()启动方法中,会将一个SimpleContextLifecycleListener实例与SimpleContext绑定起来。
下面是SimpleContext的部分代码
public class SimpleContext implements Context, Pipeline, Lifecycle {
public SimpleContext() {
pipeline.setBasic(new SimpleContextValve());
}
// 子容器
protected HashMap children = new HashMap();
// 载入器
private Loader loader = null;
// 生命周期支持组件
protected LifecycleSupport lifecycle = new LifecycleSupport(this);
// 管道
private SimplePipeline pipeline = new SimplePipeline(this);
// servlet的uri映射
private HashMap servletMappings = new HashMap();
// 默认映射器
protected Mapper mapper = null;
// 映射器集合
protected HashMap mappers = new HashMap();
// 父组件
private Container parent = null;
// 此组件是否已启动
protected boolean started = false;
// 添加映射器
public void addLifecycleListener(LifecycleListener listener) {
lifecycle.addLifecycleListener(listener);
}
// 移除映射器
public void removeLifecycleListener(LifecycleListener listener) {
lifecycle.removeLifecycleListener(listener);
}
public synchronized void start() throws LifecycleException {
if (started) {
throw new LifecycleException("SimpleContext has already started");
}
// 触发了特定事件,通知事件监听器
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
started = true;
try {
// 启动所有从属组件
if ((loader != null) && (loader instanceof Lifecycle)) {
((Lifecycle) loader).start();
}
// 启动所有子容器
Container children[] = findChildren();
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Lifecycle) {
((Lifecycle) children[i]).start();
}
}
// 启动管道中的所有阀
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).start();
}
// 触发了特定事件,通知事件监听器
lifecycle.fireLifecycleEvent(START_EVENT, null);
} catch (Exception e) {
e.printStackTrace();
}
// 触发了特定事件,通知事件监听器
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}
public void stop() throws LifecycleException {
if (!started) {
throw new LifecycleException("SimpleContext has not been started");
}
// 触发了特定事件,通知事件监听器
lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
started = false;
try {
// 关闭管道中的所有阀
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).stop();
}
// 关闭所有子容器
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();
}
// 触发了特定事件,通知事件监听器
lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
}
}
SimpleContextLifecycleListener监听器
public class SimpleContextLifecycleListener implements LifecycleListener {
public void lifecycleEvent(LifecycleEvent event) {
Lifecycle lifecycle = event.getLifecycle();
System.out.println("SimpleContextLifecycleListener's event " + event.getType());
if (Lifecycle.START_EVENT.equals(event.getType())) {
System.out.println("Starting context.");
} else if (Lifecycle.STOP_EVENT.equals(event.getType())) {
System.out.println("Stopping context.");
}
}
}
SimpleLoader(载入器)实现了Lifecycle接口,但是方法都留空了,start与stop方法打印了一下启动信息。虽然这里start方法没有干事,但是它的启动流程已经能交给上层组件来控制了,后面再丰富启动流程也ok。
public synchronized void start() throws LifecycleException {
System.out.println("Starting SimpleLoader");
}
public void stop() throws LifecycleException {
System.out.println("Stopping SimpleLoader");
}
SimplePipeline实现了Lifecycle接口,但是相关方法也留空了。start与stop方法仅仅打印一条信息。
public synchronized void start() throws LifecycleException {
System.out.println("Starting SimplePipeline");
}
public void stop() throws LifecycleException {
System.out.println("Stopping SimplePipeline");
}
SimpleWrapper实现了Lifecycle接口,它是个容器类,包含了多种组件,所以它的start(),stop()方法做了实现。由于SimpleWrapper的每个实例都对应了一个servlet实例,所以在stop方法中,会去调用servlet的destroy方法。
public class SimpleWrapper implements Wrapper, Pipeline, Lifecycle {
public SimpleWrapper() {
pipeline.setBasic(new SimpleWrapperValve());
}
// the servlet instance
private Servlet instance = null;
private String servletClass;
private Loader loader;
private String name;
private SimplePipeline pipeline = new SimplePipeline(this);
protected Container parent = null;
protected LifecycleSupport lifecycle = new LifecycleSupport(this);
protected boolean started = false;
// 本章中的SimpleWrapper没有监听器,监听器相关的三个方法留空
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");
}
// 触发了特定事件,通知事件监听器
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
started = true;
// 启动所有从属组件
if ((loader != null) && (loader instanceof Lifecycle)) {
((Lifecycle) loader).start();
}
// 启动管道中的所有阀
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).start();
}
// 触发了特定事件,通知事件监听器
lifecycle.fireLifecycleEvent(START_EVENT, null);
// 触发了特定事件,通知事件监听器
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}
public void stop() throws LifecycleException {
System.out.println("Stopping wrapper " + name);
// 销毁servlet实例 (如果它已经被初始化的话)
try {
instance.destroy();
} catch (Throwable t) {
}
instance = null;
if (!started) {
throw new LifecycleException("Wrapper " + name + " not started");
}
// 触发了特定事件,通知事件监听器
lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
// 触发了特定事件,通知事件监听器
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
started = false;
// 关闭管道中的所有阀
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).stop();
}
// 关闭所有从属组件
if ((loader != null) && (loader instanceof Lifecycle)) {
((Lifecycle) loader).stop();
}
// 触发了特定事件,通知事件监听器
lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
}
}
启动类与第五章相比,还是原来的配方,还是原来的味道。
public final class Bootstrap {
public static void main(String[] args) {
Connector connector = new HttpConnector();
Wrapper wrapper1 = new SimpleWrapper();
wrapper1.setName("Primitive");
wrapper1.setServletClass("PrimitiveServlet");
Wrapper wrapper2 = new SimpleWrapper();
wrapper2.setName("Modern");
wrapper2.setServletClass("ModernServlet");
Context context = new SimpleContext();
context.addChild(wrapper1);
context.addChild(wrapper2);
Mapper mapper = new SimpleContextMapper();
mapper.setProtocol("http");
LifecycleListener listener = new SimpleContextLifecycleListener();
((Lifecycle) context).addLifecycleListener(listener);
context.addMapper(mapper);
Loader loader = new SimpleLoader();
context.setLoader(loader);
// context.addServletMapping(pattern, name);
context.addServletMapping("/Primitive", "Primitive");
context.addServletMapping("/Modern", "Modern");
connector.setContainer(context);
try {
connector.initialize();
((Lifecycle) connector).start();
((Lifecycle) context).start();
// make the application wait until we press a key.
System.in.read();
((Lifecycle) context).stop();
} catch (Exception e) {
e.printStackTrace();
}
}
}
启动应用,看后端日志
HttpConnector Opening server socket on all host IP addresses
HttpConnector[8080] Starting background thread
SimpleContextLifecycleListener's event before_start
Starting SimpleLoader
Starting Wrapper Primitive
Starting SimplePipeline
Starting Wrapper Modern
Starting SimplePipeline
Starting SimplePipeline
SimpleContextLifecycleListener's event start
Starting context.
SimpleContextLifecycleListener's event after_start
关闭应用
SimpleContextLifecycleListener's event before_stop
SimpleContextLifecycleListener's event stop
Stopping context.
Stopping SimplePipeline
Stopping wrapper Primitive
Stopping SimplePipeline
Stopping wrapper Modern
Stopping SimplePipeline
Stopping SimpleLoader
SimpleContextLifecycleListener's event after_stop
Process finished with exit code 0
可以看到,随着SimpleContext#start()方法的调用,其下属的各组件和子容器都被启动了起来。而当我往控制台中输入了内容(“关闭应用”)之后,触发关闭流程,随着SimpleContext#stop()方法的调用,其下属各组件与子容器也都被关闭了。由于SimpleContext与SimpleWraper容器实例中都包含SimplePipeline所以你能看到多条SimplePipeline的启动信息。
好,本章内容到此结束。Tomcat通过Lifecycle这么一组接口,将各个组件的生命周期串联了起来,实现了“一键启动”、“一键关闭”。这个思想值得借鉴,体悟这种编程思想,也为我们以后的编程场景多一种参考储备。下一章,我们一起来看看Tomcat中的日志记录器,看看它是怎么记日志的,敬请期待吧!
源码分享
https://gitee.com/huo-ming-lu/HowTomcatWorks
原书中的代码没有明显bug,所以我仅仅格式化了一下代码,并加了些注释