本文主要介绍tomcat启动过程中,从server到context这一部分,主要涉及Lifecycle。
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();
}
上面是Lifecycle接口,我把注释都去掉了,接口定义中开始部分的static域(如:BEFORE_INIT_EVENT)是Lifecycle中支持的各种事件。之前我们提到过,Lifecycle实现了一个观察者模式,而上面这些事件就代表了tomcat中各个组件生命周期中的各个事件,当这些事件发生的时候,会通知感兴趣的观察者(LifecycleListener)。
Lifecycle在tomcat中被使用的很多,用来管理tomcat中各个组件的生命周期,之前的博文中我们提到过的server、service、connector、engine、host、context等,他们都派生了Lifecycle接口。
Lifecycle中还声明了几个很重要的方法:init、start、stop、destroy。这几个方法共同构成了组件的生命周期,init-初始化,start-启动,stop-停止,destroy-销毁。再看看上面的那些事件,实际上都是和这里的几个生命周期对应的,每个生命周期XXX,都包括beforeXXX、XXX、afterXXX这三个事件。各个组件在tomcat启动之后,到shutdown之前,就会经历这样的生命周期过程,从一开始初始化,最后被销毁,中间可能会经历start、stop、start、stop,起起落落。就像人诞生下来,不管中间过得多么精彩,但最终的结果还是会死亡。
Tomcat分成很多的组件,这些组件需要分别启动,我们已经知道Lifecycle中声明的start的方法就是用来完成这项工作的。这些组件都派生了Lifecycle接口,分别实现了Lifecycle里的方法,也就拥有了管理自己生命周期(初始化、启动、停止、销毁)的能力。
接下来,我们分析下各个组件是怎么样完成启动过程的。
一个Server就代表了整个catalina servlet容器。因此,他的属性,也能代表了整个servlet容器的特性。整个servlet的生命周期都由server控制。
我们在启动tomcat的时候,首先会创建一个单例的server对象(实际上是StandardServer对象,我们之前提到过,一个tomcat中,只会有一个server),然后进行初始化(init),之后会调用server的start方法,用来启动server。
我们也提到过server中包含service,可能是一个或者多个。
/**
* The set of Services associated with this Server.
*/
private Service services[] = new Service[0];
/**
* 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 (services) {
for (int i = 0; i < services.length; i++) {
services[i].start();
}
}
}
Server的start方法中,会调用上面的startInternal()方法。在startInternal()方法中,我们可以看到,server会将自己所拥有的service全部给start-启动。
Service中,有2种tomcat中最重要的组件:connector、container。Connector用来接收浏览器的请求,一个service中可以有多个connector。Container主要有3种,分别是engine、host、context,service直接包含的是engine,engine包含host,host包含context,一个service只能有一个engine。
/**
* The set of Connectors associated with this Service.
*/
protected Connector connectors[] = new Connector[0];
/**
* The Container associated with this Service. (In the case of the
* org.apache.catalina.startup.Embedded subclass, this holds the most
* recently added Engine.)
*/
protected Container container = null;
/**
* Start nested components ({@link Executor}s, {@link Connector}s and
* {@link Container}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 {
if(log.isInfoEnabled())
log.info(sm.getString("standardService.start.name", this.name));
setState(LifecycleState.STARTING);
// Start our defined Container first
if (container != null) {
synchronized (container) {
container.start();
}
}
synchronized (executors) {
for (Executor executor: executors) {
executor.start();
}
}
// Start our defined Connectors second
synchronized (connectors) {
for (Connector connector: connectors) {
try {
// If it has already failed, don't try and start it
if (connector.getState() != LifecycleState.FAILED) {
connector.start();
}
} catch (Exception e) {
log.error(sm.getString(
"standardService.connector.startFailed",
connector), e);
}
}
}
}
同server一样,service的start方法会调用他所拥有的container和connector的start方法。
如此一来,就相当于形成了一条链,server启动的时候会去启动service,service启动的时候又会顺道把container和connector启动了。
剩下的就是container的启动了,service启动的container,实际上就是engine(StandardEngin)。
容器的start方法和server、service的有点不一样,因为容器有一个包含关系,父容器包含子容器。父容器启动的时候,会顺道将自己所有的子容器启动,顶层的容器是engine,他的子容器是一个或多个host,engine启动的时候,会将他拥有的所有host启动,然后host启动的时候,又会将context启动。
/**
* Start this component 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 synchronized void startInternal() throws LifecycleException {
// Start our subordinate components, if any
if ((loader != null) && (loader instanceof Lifecycle))
((Lifecycle) loader).start();
logger = null;
getLogger();
if ((manager != null) && (manager instanceof Lifecycle))
((Lifecycle) manager).start();
if ((cluster != null) && (cluster instanceof Lifecycle))
((Lifecycle) cluster).start();
Realm realm = getRealmInternal();
if ((realm != null) && (realm instanceof Lifecycle))
((Lifecycle) realm).start();
if ((resources != null) && (resources instanceof Lifecycle))
((Lifecycle) resources).start();
// Start our child containers, if any
Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<Future<Void>>();
for (int i = 0; i < children.length; i++) {
results.add(startStopExecutor.submit(new StartChild(children[i])));
}
boolean fail = false;
for (Future<Void> result : results) {
try {
result.get();
} catch (Exception e) {
log.error(sm.getString("containerBase.threadedStartFailed"), e);
fail = true;
}
}
if (fail) {
throw new LifecycleException(
sm.getString("containerBase.threadedStartFailed"));
}
// Start the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
setState(LifecycleState.STARTING);
// Start our thread
threadStart();
}
如是, tomcat 启动过程中各个组件的启动流程。