在上一篇文章中:Tomcat服务器顶层结构和启动过程 对Tomcat的整体架构有了一个大致的了解,这一篇主要是学习一下Tomcat的整个生命周期的管理。
Tomcat的生命周期管理使用了观察者模式,使Tomcat的生命周期管理机制设计的非常优雅,在Tomcat启动时,只需要启动一个Server组件,就会启动所有的容器及对应的组件,并且触发这些容器的监听者,完成启动过程的设置。可以说是“一键式”启动的。停止过程也是一样。
一、观察者模式简单描述
(1)观察者模式有时被称作:发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
观察者模式的应用非常广泛,如Java AWT事件模型,Servlet的监听器,Spring事件处理机制以及Tomcat生命周期管理机制等等。
(2)观察者模式解决的问题
将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。观察者就是解决这类的耦合关系的。
(3)观察者模式中有3类角色对象:
1、抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
2、具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
3、抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
4、具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
(4)观察者模式的类图:
二、Tomcat的生命周期管理相关类
关于Tomcat的生命周期管理所涉及的相关类主要有:
(1)Lifecycle:相当于抽象主题角色,所有的容器类与组件实现类都实现了这个接口。如StandardContext
(2)LifecycleListener:相当于抽象观察者角色,具体的实现类有ContextConfig, HostConfig, EngineConfig类,它们在容器启动时与停止时触发。
(3)LifecycleEvent:生命周期事件,对主题与发生的事件进行封装。
(4)LifecycleSupport:生命周期管理的实用类,提供对观察者的添加,删除及通知观察者的方法。(Tomcat release 9.0.x版本中没有用到这个)
(5)LifecycleException:生命周期异常类。
三、Lifecycle接口介绍
组件生命周期方法的通用接口。org.apache.catalina.Lifecycle
Tomcat通过Lifecycle接口统一管理生命周期,所有有生命周期的组件都要实现Lifecycle接口,以便提供一致的机制去启动和停止组件。Lifecycle接口内容如下:
上图中可以看出Lifecycle接口一共做了四件事情:
(1)定义了13个String类型常量:这些常量信息用于LifecycleEvent事件的type属性中,作用是区分组件发出的LifecycleEvent事件是的状态(如初始化前、启动前、启动中等)。这种设计方法可以让多种状态都发送同一种类型的时间,然后用其中的一个属性类区分状态而不用定义多种事件。
(2)定义了3个管理监听器的方法:addLifecycleListener、findLifecycleListeners和removeLifecycleListener。分别用来添加、查找和删除LifecycleListener类型的监听器。源码如下图所示:
(3)定义了4个生命周期的方法:init、start、stop和destory,用于执行生命周期的各个阶段,接口定义如下:
public void init() throws LifecycleException;
public void start() throws LifecycleException;
public void stop() throws LifecycleException;
public void destroy() throws LifecycleException;
(4)定义了获取当前和状态的两个方法: getState和getStateName,用来获取当前的状态,getState的返回值LifecycleState是枚举类型,里边列举了生命周期的各个节点,getStateName方法返回String类型的状态的名字。
完整的Lifecycle 接口定义代码如下:
package org.apache.catalina;
public interface Lifecycle {
public static final String BEFORE_INIT_EVENT = "before_init";
public static final String AFTER_INIT_EVENT = "after_init";
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 static final String AFTER_DESTROY_EVENT = "after_destroy";
public static final String BEFORE_DESTROY_EVENT = "before_destroy";
public static final String PERIODIC_EVENT = "periodic";
public static final String CONFIGURE_START_EVENT = "configure_start";
public static final String CONFIGURE_STOP_EVENT = "configure_stop";
public void addLifecycleListener(LifecycleListener listener);
public LifecycleListener[] findLifecycleListeners();
public void removeLifecycleListener(LifecycleListener listener);
public void init() throws LifecycleException;
public void start() throws LifecycleException;
public void stop() throws LifecycleException;
public void destroy() throws LifecycleException;
public LifecycleState getState();
public String getStateName();
public interface SingleUse {
}
}
四、Lifecycle接口默认实现LifecycleBase
Lifecycle接口的默认实现是org.apache.catalina.util.LifecycleBase
,在LifecycleBase实现类中实现了Lifecycle接口中定义的方法,类结构图如下:
(1)3个管理监听器的方法
private final List<LifecycleListener> lifecycleListeners = new CopyOnWriteArrayList<>();
@Override
public void addLifecycleListener(LifecycleListener listener) {
lifecycleListeners.add(listener);
}
@Override
public LifecycleListener[] findLifecycleListeners() {
return lifecycleListeners.toArray(new LifecycleListener[0]);
}
@Override
public void removeLifecycleListener(LifecycleListener listener) {
lifecycleListeners.remove(listener);
}
可以看出LifecycleBase定义了一个lifecycleListeners 集合用于保存所有的监听器,然后并定义了添加、删除、查找和执行监听器的方法;
(2)4个生命周期的方法:init、start、stop和destory
protected abstract void initInternal() throws LifecycleException;
@Override
public final synchronized void init() throws LifecycleException {
//开始的状态必须是LifecycleState.NEW,否则会抛出异常
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
try {
//在初始化之前,将状态设置为LifecycleState.INITIALIZING 表示正在初始化中
setStateInternal(LifecycleState.INITIALIZING, null, false);
//使用模板的方式进行具体的初始化,该抽象方法是由子类实现的
initInternal();
//在初始化之后,将状态设置为LifecycleState.INITIALIZED 表示初始化完成
setStateInternal(LifecycleState.INITIALIZED, null, false);
} catch (Throwable t) {
handleSubClassException(t, "lifecycleBase.initFail", toString());
}
}
这里对四个生命周期,只讨论init方法,其他三种大致相同。
在init方法中调用了所对应的模板方法initInternal()
该方法并没有具体的实现,而是让子类去具体的实现,因此对于子类来说,执行生命周期的方法就是:initInternal、startInternal、stopInternal、destroyInternal;
(3)定义了获取当前和状态的两个方法:getState和getStateName
private volatile LifecycleState state = LifecycleState.NEW;
@Override
public LifecycleState getState() {
return state;
}
@Override
public LifecycleState getState() {
return state;
}
@Override
public String getStateName() {
return getState().toString();
}
在生命周期相应的方法中已经设置了state的属性,所以通过这两个方法就可以简单的实现获取state。
五、再谈Tomcat中的观察者模式
Tomcat中的观察者模式:
Tomcat中Lifecycle就是抽象的主题。
然后像StandardEngine、StandardHost、StandardContext、StandardServer这类Container对象,都是具体主题。
LifecycleListener定义了观察者想要执行的方法。就是前面提到的,如果观察者对主题的某个动作感兴趣,他就会做自己的动作,这个动作就是LifecycleListener里的方法。当然LifecycleListener是一个接口,用户可以定义各种具体的观察者。
Tomcat对观察者模式做了很好的扩展,他增加了一个LifecycleSupport来代替主题管理多个观察者,把功能模块分得更清晰,LifecycleSupport中定义了一个LifecycleListener的数组。主题中某动作发生时,LifecycleSupport会遍历此数组,对每一个listener调用它们像要做的方法。
下面的方法就是LifecycleSupport通知各个LifecycleListener某事件发生了。
/**
* Notify all lifecycle event listeners that a particular event has
* occurred for this Container. The default implementation performs
* this notification synchronously using the calling thread.
*
* @param type Event type
* @param data Event data
*/
public void fireLifecycleEvent(String type, Object data) {
LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
LifecycleListener interested[] = listeners;
for (int i = 0; i < interested.length; i++)
interested[i].lifecycleEvent(event);
}
Tomcat中将事件定义为LifecycleEvent
/**
* Construct a new LifecycleEvent with the specified parameters.
*
* @param lifecycle Component on which this event occurred
* @param type Event type (required)
* @param data Event data (if any)
*/
public LifecycleEvent(Lifecycle lifecycle, String type, Object data) {
super(lifecycle);
this.type = type;
this.data = data;
}
事件有一个属性type,用来标明事件的类型。
也就是说Tomcat中观察者模式流程:
1、将观察者listener增加到LifecycleSupport的listener数组中
2、当container(主题)做某些动作的时候,会生成一个LifecycleEvent对象,这个对象标明当前这个动作是一个什么事件,然后LifecycleSupport会通知listener数组中的每一个观察者该事件的发生。
3、listener会根据LifecycleEvent判断事件的类型,完成相应的动作。
参考文章:
1、https://my.oschina.net/u/227422/blog/66213
2、http://www.cnblogs.com/chenying99/archive/2012/09/05/2671199.html