【转】Tomcat组件生命周期管理

时间:2021-12-31 15:44:13

Tomcat组件生命周期管理

Tomcat中Server,Service,Connector,Engine,Host,Context,它们都实现了org.apache.catalina.Lifecycle接口,而org.apache.catalina.util.LifecycleBase采用了模板方法模式来对所有支持生命周期管理的组件的生命周期各个阶段进行了总体管理,每个需要生命周期管理的组件只需要继承这个基类,然后覆盖对应的钩子方法即可完成相应的生命周期阶段性的管理工作。 下面我们首先来看看org.apache.catalina.Lifecycle接口的定义,它的类图如下图所示:【转】Tomcat组件生命周期管理从上图我们可以清楚的看到LifeCycle中主要有四个生命周期阶段,它们分别是init(初始化),start(启动),stop(停止),destory(销毁)。知道了这四个生命周期阶段以后,咋们就来看看org.apache.catalina.util.LifecycleBase是如何实现模板方法模式的。 那接下来我们就来看看org.apache.catalina.util.LifecycleBase类的定义,它的类图如下所示:【转】Tomcat组件生命周期管理上图中用红色标注的四个方法就是模板方法模式中的钩子方法,子类可以通过实现钩子方法来纳入到基类已经流程化好的生命周期管理中。
上面我们对LifeCycle和LifeCycleBase有了一个总体的认识,接下来,我们通过查看org.apache.catalina.util.LifecycleBase的源代码来具体的分析一下。 咋们首先来看org.apache.catalina.util.LifecycleBase的init方法的实现。

org.apache.catalina.util.LifecycleBase#init

@Override
public final synchronized void init() throws LifecycleException {
//
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
setStateInternal(LifecycleState.INITIALIZING, null, false); try {
// 2 钩子
initInternal();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
setStateInternal(LifecycleState.FAILED, null, false);
throw new LifecycleException(
sm.getString("lifecycleBase.initFail",toString()), t);
}
// 3
setStateInternal(LifecycleState.INITIALIZED, null, false);
}

下面我们逐一来分析一下上述代码中标注了数字的地方:

  1. 标注1的代码首先检测当前组件的状态是不是NEW(新建),如果不是就调用org.apache.catalina.util.LifecycleBase#invalidTransition方法来将当前的状态转换过程终止,而invalidTransition的实现是抛出了org.apache.catalina.LifecycleException异常。接着调用了setStateInternal方法将状态设置为INITIALIZING(正在初始化)
  2. 标注2的代码就是init模板方法的钩子,子类可以通过实现protected abstract void initInternal() throws LifecycleException;方法来纳入初始化的流程。
  3. 标注3的代码将组件的状态改为INITIALIZED(已初始化)。

上面我们分析了init模板方法,接下来我们再看看start方法具体做了什么事情。start的代码如下:

org.apache.catalina.util.LifecycleBase#start

public final synchronized void start() throws LifecycleException {
//
if (LifecycleState.STARTING_PREP.equals(state) ||
LifecycleState.STARTING.equals(state) ||
LifecycleState.STARTED.equals(state)) { if (log.isDebugEnabled()) {
Exception e = new LifecycleException();
log.debug(sm.getString("lifecycleBase.alreadyStarted",
toString()), e);
} else if (log.isInfoEnabled()) {
log.info(sm.getString("lifecycleBase.alreadyStarted",
toString()));
} return;
} //
if (state.equals(LifecycleState.NEW)) {
init();
} else if (state.equals(LifecycleState.FAILED)){
stop();
} else if (!state.equals(LifecycleState.INITIALIZED) &&
!state.equals(LifecycleState.STOPPED)) {
invalidTransition(Lifecycle.BEFORE_START_EVENT);
}
//
setStateInternal(LifecycleState.STARTING_PREP, null, false); try {
//4 钩子
startInternal();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
setStateInternal(LifecycleState.FAILED, null, false);
throw new LifecycleException(
sm.getString("lifecycleBase.startFail",toString()), t);
} //
if (state.equals(LifecycleState.FAILED) ||
state.equals(LifecycleState.MUST_STOP)) {
stop();
} else {
// Shouldn't be necessary but acts as a check that sub-classes are
// doing what they are supposed to.
if (!state.equals(LifecycleState.STARTING)) {
invalidTransition(Lifecycle.AFTER_START_EVENT);
} setStateInternal(LifecycleState.STARTED, null, false);
}
}

下面我们逐一来分析一下上述代码中标注了数字的地方:

  1. 标注1的代码检测当前组件的状态是不是STARTING_PREP(准备启动),STARTING(正在启动),STARTED(已启动).如果是这三个状态中的任何一个,则抛出LifecycleException
  2. 标注2的代码的检查其实主要是为了保证组件状态的完整性,在正常启动的流程中,应该是不会出现没有初始化就启动,或者还没启动就已经失败的情况。
  3. 标注3的代码设置组件的状态为STARTING_PREP(准备启动状态)
  4. 标注4的代码是start模板方法的钩子方法,子类通过实现org.apache.catalina.util.LifecycleBase#startInternal这个方法来纳入到组件启动的流程中来。
  5. 标注5的代码做了一些状态检查,然后最终将组件的状态设置为STARTED(已启动)

上面我们分析了init和start方法的流程,对于stop和destroy方法的总体过程是类似的,大家可以自己阅读一下,但是通过上面的分析,我们可以得出生命周期方法的总体的骨架,如果用伪代码来表示可以简化为如下:

org.apache.catalina.util.LifecycleBase#lifeCycleMethod

    public final synchronized void lfieCycleMethod() throws LifecycleException {
stateCheck();//状态检查
//设置为进入相应的生命周期之前的状态
setStateInternal(LifecycleState.BEFORE_STATE, null, false);
lfieCycleMethodInternal();//钩子方法
//进入相应的生命周期之后的状态
setStateInternal(LifecycleState.AFTER_STATE, null, false);
}

Reference:

Tomcat启动过程(Tomcat源代码阅读系列之三)