类概况
关注这个类是因为上一回跟踪了AccessLogValve类,它是LifecycleMBeanBase的一个子类,搞清楚这个类的各个子类结构,也就理顺了Tomcat容器中各个组件的协助流程了。管中窥豹,还是先从这个顶层抽象类开始吧。
这个类的结构很简单,类图绘制如下:
父类LifecycleBase
Base implementation of the Lifecycle interface that implements the
state transition rules for start() and stop()
这是源码的注释,说明了这个类是Lifecycle接口的基本实现类,Tomcat中的组件都需要实现Lifecycle接口,以提供一种标准的流程来启动和关闭组件。从类图来看,它主要提供了跟组件生命周期有关的方法,如启动、停止、销毁。
值得关注的是,它是一个抽象类,而且除了跟LifecycleListener有关的方法外,其他方法都是成对出现:例如start(),startInternal()。这是典型的模版方法设计模式的运用,start()方法是公共final的模版方法,定义了启动流程,而流程中的各个操作都是protected abstract方法,由子类提供且只能由子类调用。源码如下:
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);
}
try {
setStateInternal(LifecycleState.STARTING_PREP, null, false);
startInternal();
if (state.equals(LifecycleState.FAILED)) {
// This is a 'controlled' failure. The component put itself into the
// FAILED state so call stop() to complete the clean-up.
stop();
} else if (!state.equals(LifecycleState.STARTING)) {
// Shouldn't be necessary but acts as a check that sub-classes are
// doing what they are supposed to.
invalidTransition(Lifecycle.AFTER_START_EVENT);
} else {
setStateInternal(LifecycleState.STARTED, null, false);
}
} catch (Throwable t) {
}
}
其他几个方法基本类似。
此外,这是一个简单的观察者模式的应用,LifecycleBase和LifecycleSupport是观察者模式实现的两个类。触发LifecycleEvent事件时根据当前lifecycle对象创建事件,然后以此通知列表中的监听者。
LifecycleMBeanBase
JmxEnable是Java Managed Bean相关的功能,这个还有待继续研究。它也是个抽象类,实现了父类的initInternal()和destroyInternal(),这两个方法也很简单,就是对ManabedBean的注册和注销。源码如下:
protected void initInternal() throws LifecycleException {
// If oname is not null then registration has already happened via
// preRegister().
if (oname == null) {
mserver = Registry.getRegistry(null, null).getMBeanServer();
oname = register(this, getObjectNameKeyProperties());
}
}
@Override
protected void destroyInternal() throws LifecycleException {
unregister(oname);
}
注意类图中,LifecycleMBeanBase类的getDomain方法定义的是final类型,它调用了getInternalDomain()这个protected abstract方法,这也是典型的模版方法模式的应用。
启示录
首先,就是模版方法的运用,值得学习。
其次,这个类图中有两个接口,可以发现Tomcat源码中接口方法中通常会定义一对getXX,setXX这样的方法,那么它的实现类必定会有一个这样类型的成员变量。
此外,还可以通过委派其他类来实现接口中的方法。例如LifecycleBase方法中对LifecycleEventListener的支持就是通过成员变量lifecycle:LifecycleSupport实现的。这种类的设计思路,总结一下还是很受启发的。
最后,就是protected权限的巧妙运用,LifecycleBase中以Internal为后缀的那些方法,可以理解为是内部方法,只有自己和子类才能调用。这也解答了我的疑虑:之前我在想如果调用者直接调用startInternal方法而不调start怎么办呢?