从Tomcat启动开始的源码分析
Tomcat启动分析
承接上文,Catalina类通过load方法创建digester对象解析server.xml文件以获取Server对象.接下来就是Server启动流程的分析.
1. Server的启动方法是源自哪里?
查看org.apache.catalina.Server接口的定义,可以看出start()方法是继承自org.apache.catalina.Lifecycle接口.Tomcat通过Lifecycle接口提供统一的组件生命周期管理.Lifecycle的接口注释很有趣,通过它可以很直观的了解组件生命周期管理流程,所以我把它贴进来.
/*
* start()
* -----------------------------
* | |
* | init() |
* NEW -»-- INITIALIZING |
* | | | | ------------------«-----------------------
* | | |auto | | |
* | | \|/ start() \|/ \|/ auto auto stop() |
* | | INITIALIZED --»-- STARTING_PREP --»- STARTING --»- STARTED --»--- |
* | | | | |
* | |destroy()| | |
* | --»-----«-- ------------------------«-------------------------------- ^
* | | | |
* | | \|/ auto auto start() |
* | | STOPPING_PREP ----»---- STOPPING ------»----- STOPPED -----»-----
* | \|/ ^ | ^
* | | stop() | | |
* | | -------------------------- | |
* | | | | |
* | | | destroy() destroy() | |
* | | FAILED ----»------ DESTROYING ---«----------------- |
* | | ^ | |
* | | destroy() | |auto |
* | --------»----------------- \|/ |
* | DESTROYED |
* | |
* | stop() |
* ----»-----------------------------»------------------------------
*/
讲到接口不能只看方法签名呀,我们得找出接口的实现.还记得上文讨论Catalina类的load方法获取一个Server实例吗?这个Server接口的实例就来自于load中调用的createStartDigester方法.当时贴了一大段代码,可能你没注意到Server接口的实例,就在此时映射上去的:
// Configure the actions we will be using
digester.addObjectCreate("Server",
"org.apache.catalina.core.StandardServer",
"className");
digester.addSetProperties("Server");
digester.addSetNext("Server",
"setServer",
"org.apache.catalina.Server");
看到这里我们就知道,Tomcat为每个组件接口提供了标准的实现类,Server接口对应的就是StandardServer.
2. StandardServer的启动方法是如何实现的?
StandardServer 类体里面没有实现start方法,而是通过继承生命周期管理基类LifecycleMBeanBase实现这一特性.而LifecycleMBeanBase继承了LifecycleBase.最后是LifecycleBase实现了Lifecycle接口.
这样做有啥好处呢?还是那句话组件之间生命周期的统一管理,把生命周期管理可重用部分的部分抽象出来,把需要组件定制的流程通过抽象方法延迟到子类中实现.
通过阅读LifecycleBase代码实现,我们可以看到init\start\stop\destroy中都有一些流程通过抽象方法延迟到StandardServer子类中实现.
/**
* {@inheritDoc}
*/
@Override
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) {
// This is an 'uncontrolled' failure so put the component into the
// FAILED state and throw an exception.
handleSubClassException(t, "lifecycleBase.startFail", toString());
}
}
/**
* Sub-classes must ensure that the state is changed to
* {@link LifecycleState#STARTING} during the execution of this method.
* Changing state will trigger the {@link Lifecycle#START_EVENT} event.
*
* If a component fails to start it may either throw a
* {@link LifecycleException} which will cause it's parent to fail to start
* or it can place itself in the error state in which case {@link #stop()}
* will be called on the failed component but the parent component will
* continue to start normally.
*
* @throws LifecycleException Start error occurred
*/
protected abstract void startInternal() throws LifecycleException;
/**
* Sub-classes implement this method to perform any instance initialisation
* required.
*
* @throws LifecycleException If the initialisation fails
*/
protected abstract void initInternal() throws LifecycleException;
/**
* Sub-classes must ensure that the state is changed to
* {@link LifecycleState#STOPPING} during the execution of this method.
* Changing state will trigger the {@link Lifecycle#STOP_EVENT} event.
*
* @throws LifecycleException Stop error occurred
*/
protected abstract void stopInternal() throws LifecycleException;
/**
* Sub-classes implement this method to perform any instance destruction
* required.
*
* @throws LifecycleException If the destruction fails
*/
protected abstract void destroyInternal() throws LifecycleException;
3. StandardServer中startInternal()方法实现.
/**
* Start nested components ({@link Service}s) and implement the requirements
* of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
*
* @exception LifecycleException if this component detects a fatal error
* that prevents this component from being used
*/
@Override
protected void startInternal() throws LifecycleException {
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING);
globalNamingResources.start();
// Start our defined Services
synchronized (servicesLock) {
for (int i = 0; i < services.length; i++) {
services[i].start();
}
}
if (periodicEventDelay > 0) {
monitorFuture = getUtilityExecutor().scheduleWithFixedDelay(
new Runnable() {
@Override
public void run() {
startPeriodicLifecycleEvent();
}
}, 0, 60, TimeUnit.SECONDS);
}
}