在繼續Tomcat啓動過程源碼分析之前,我們先回顧一下Tomcat的生命週期,查看LifeCycle.java類的註釋:
/**
* Common interface for component life cycle methods. Catalina components
* may implement this interface (as well as the appropriate interface(s) for
* the functionality they support) in order to provide a consistent mechanism
* to start and stop the component.
* <br>
* The valid state transitions for components that support {@link Lifecycle}
* are:
* <pre>
* 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() |
* ----»-----------------------------»------------------------------
*
* Any state can transition to FAILED.
*
* Calling start() while a component is in states STARTING_PREP, STARTING or
* STARTED has no effect.
*
* Calling start() while a component is in state NEW will cause init() to be
* called immediately after the start() method is entered.
*
* Calling stop() while a component is in states STOPPING_PREP, STOPPING or
* STOPPED has no effect.
*
* Calling stop() while a component is in state NEW transitions the component
* to STOPPED. This is typically encountered when a component fails to start and
* does not start all its sub-components. When the component is stopped, it will
* try to stop all sub-components - even those it didn't start.
*
* Attempting any other transition will throw {@link LifecycleException}.
*
* </pre>
* The {@link LifecycleEvent}s fired during state changes are defined in the
* methods that trigger the changed. No {@link LifecycleEvent}s are fired if the
* attempted transition is not valid.
*
* @author Craig R. McClanahan
*/
在上一篇文章中,我們提到LifecycleBase抽象類中的生命週期的各個階段,會把生命週期事件通知給註冊的監聽器,在LifeCycleBase.fireLifecycleEvent中體現。那麼監聽器又是如何接受事件的呢?其實早在Catalina.createStartDigester()中,各個容器的生命週期被註冊了最基本的監聽器,即實現了LifecycleListener接口的監聽器。
默認在Server.xml中註冊監聽器列表如下:
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<!-- Security listener. Documentation at /docs/config/listeners.html
<Listener className="org.apache.catalina.security.SecurityListener" />
-->
<!--APR library loader. Documentation at /docs/apr.html -->
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<!-- Prevent memory leaks due to use of particular java/javax APIs-->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
這裏整理createStartDigester()中除去Server.xml註冊基本的生命週期監聽器之外,還額外註冊若干重要監聽器:
- StandardEngine:EngineConfig 用於打印Engine啓動和停止日誌;
- StandardHost:HostConfig 重要監聽器,後詳;
- StandardContext:ContextConfig 重要監聽器,後詳;
在創建的過程中,各層級的容器也會顯示調用LifecycleBase.addLifecycleListener(LifecycleListener listener)方法。在發生了生命週期事件後,遍歷所有註冊的監聽器,調用生命週期監聽器的接口方法lifecycleEvent()。
以EngineHost爲例:
/**
* Process the START event for an associated Engine.
*
* @param event The lifecycle event that has occurred
*/
@Override
public void lifecycleEvent(LifecycleEvent event) {
// Identify the engine we are associated with
try {
engine = (Engine) event.getLifecycle();
} catch (ClassCastException e) {
log.error(sm.getString("engineConfig.cce", event.getLifecycle()), e);
return;
}
// Process the event that has occurred
if (event.getType().equals(Lifecycle.START_EVENT))
start();
else if (event.getType().equals(Lifecycle.STOP_EVENT))
stop();
}
發生了Lifecycle.START_EVENT事件,調用自身start()方法;發生了Lifecycle.STOP_EVENT事件,調用自身的stop()方法。
也就是說,各容器在發出生命週期事件的消息時,其註冊的每個監聽器會對這個事件進行輪詢響應。