TOMCAT包含很多组件。这些组件需要跟随TOMCAT一起启动和关闭。如何达到这种目的呢?TOMCAT引入了生命周期的概念。
生命周相关的接口和类包括
1. org.apache.catalina.Lifecycle
2. org.apache.catalina.LifecycleListener
3. org.apache.catalina.LifecycleEvent
4. org.apache.catalina.util.LifecycleSupport
下面分别介绍一下这些类
-
org.apache.catalina.Lifecycle
生命周期接口。所有想要被生命周期体系管理的对象都要继承于它。
下面是Lifecycle接口的主要方法。
//添加事件监听器
public void addLifecycleListener(LifecycleListener listener);
//查找所有的事件监听器
public LifecycleListener[] findLifecycleListeners();
//删除事件监听器
public void removeLifecycleListener(LifecycleListener listener);
//启动
public void start() throws LifecycleException;
//停止
public void stop() throws LifecycleException;
-
org.apache.catalina.LifecycleListener
生命周期监听接口。每个继承Lifecycle的对象可以添加多个监听器。
下面是LifecycleListener的主要方法。
//这个方法的内容是监听器被通知时需要做的事
public void lifecycleEvent(LifecycleEvent event);
-
org.apache.catalina.LifecycleEvent
生命周期体系的事件类。TOMCAT的生命周期事件包括以下9种:
- INIT_EVENT
- START_EVENT
- BEFORE_START_EVENT
- AFTER_START_EVENT
- STOP_EVENT
- BEFORE_STOP_EVENT
- AFTER_STOP_EVENT
- DESTROY_EVENT
- PERIODIC_EVENT
这些事件类型定义在Lifecycle接口中。可以把LifecycleEvent理解成生命周期体系中的Bean对象,一个用于传递数据的数据结构。其属性如下
//一个附加对象,没有实际用途,
//可以理解为备注(TOMCAT中有些代码用这个对象来记录日志)
//也可以直接忽略
private Object data = null;
//Lifecycle对象,触发事件的对象
private Lifecycle lifecycle = null;
//事件类型
private String type = null;
-
org.apache.catalina.util.LifecycleSupport
可以理解为助手类,实现了Lifecycle中除了start和stop之外的三个接口。其构造方法需要传入一个Lifecycle对象。在TOMCAT中很多Lifecycle的实例会使用LifecycleSupport类来为自己管理事件监听器。看一下LifecycleSupport的主要代码。
//构造函数,持有一个Lifecycle的引用
public LifecycleSupport(Lifecycle lifecycle) {
super();
this.lifecycle = lifecycle;
}
//Lifecycle的引用
private Lifecycle lifecycle = null;
//用于维护当前Liftcycle的监听器列表
private LifecycleListener listeners[] = new LifecycleListener[0];
//添加/移除监听器的时候需要加锁,这是加锁使用的锁对象
private final Object listenersLock = new Object(); // Lock object for changes to listeners
//添加监听器,向listeners中加入一个监听器对象
public void addLifecycleListener(LifecycleListener listener) {
synchronized (listenersLock) {
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) {
if (Lifecycle.INIT_EVENT.equals(type)) {
state = "INITIALIZED";
} else if (Lifecycle.BEFORE_START_EVENT.equals(type)) {
state = "STARTING_PREP";
} else if (Lifecycle.START_EVENT.equals(type)) {
state = "STARTING";
} else if (Lifecycle.AFTER_START_EVENT.equals(type)) {
state = "STARTED";
} else if (Lifecycle.BEFORE_STOP_EVENT.equals(type)) {
state = "STOPPING_PREP";
} else if (Lifecycle.STOP_EVENT.equals(type)) {
state = "STOPPING";
} else if (Lifecycle.AFTER_STOP_EVENT.equals(type)) {
state = "STOPPED";
} else if (Lifecycle.DESTROY_EVENT.equals(type)) {
state = "DESTROYED";
}
LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
LifecycleListener interested[] = listeners;
for (int i = 0; i < interested.length; i++)
interested[i].lifecycleEvent(event);
}
//移除监听器,在listeners中移除一个监听器对象
public void removeLifecycleListener(LifecycleListener listener) {
synchronized (listenersLock) {
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;
}
}
生命周期体系的使用
上面我们简单描述了一下生命周期体系中相关的一些类。接下来我们看一下这个体系的简单使用方法。
- MyLifecycle中初始化一个LifecycleSupport类。
- 在程序中使用LifecycleSupport的 addLifecycleListener 方法,为 MyLifecycle注册监听器。
- 当MyLifecycle的状态发生变化的时候,开发者就可以调用LifecycleSupport的 fireLifecycleEvent 方法触发事件,告知所有注册的监听器:“XXX事件发生了”。
- fireLifecycleEvent 方法会调用监听器(LifecycleListener)的 lifecycleEvent 方法来处理对应的事件。由于LifecycleListener只是个接口,所以具体的处理逻辑在监听器的实现类中实现。
再说说之前忽略的 start 和 stop 方法
TOMCAT容器的启动和关闭全都依赖于各容器的 start 和 stop 方法。众所周知TOMCAT的容器是有层级关系的,如: 父容器 Context 和子容器 Wrapper。Context容器启动的时候必须要去启动与他相关联的子容器Wrapper。而Context的启动又是由他的父容器来触发,以此类推。因此,TOMCAT启动时只需要调用最上层容器的 start 方法,同样的,关闭时也只需要调用最上层容器的 stop 方法。
如下图
当然TOMCAT完整的启动链肯定没有这么简单,但是我们在这里忽略其他细节,只关注 start 和 stop 方法。