Tomcat6的内部结构是以组件的形式封装的,每个组件负责一项功能。tomcat中的组件之间的有3中关系:同级组件、下属组件和子组件。同级组件也就是处于相等地位的组件,比如两个虚拟主机Host;下属组件是指一个组件的内部包含了另外一些负责实现扩展功能的组件,比如Engine组件包含了Logger组件用于实现log功能;子组件就是4个级别的容器:Engine包含Host、Host包含Context、Context包含Wrapper。
由上可见组件的种类和其之间的关系繁多,合理的处理组件之间的联系于通讯就显得非常重要了。Tomcat对于组件的通讯机制组要是采用观察者模式(Observer Pattern):组件本身实现主题接口(Subject),于其相关联的组件实现对该主题的观察者接口(Observer),并在该主题处注册。当组件本身的状态发生变化的时候,它就通知订阅了本主题的其他所有组件。在Tomcat中,主题接口表现为Lifecycle,观察者接口表现为LifecycleListener,同时,使用一个LifecycleEvent类负责传递生命周期事件的信息。与标准观察者不同的是,Tomcat还将对LifecycleListener的管理和通知工作抽取出来,独立形成一个LifecycleSupport工具类。这样做的目的主要是为了复用:各种Lifecycle就不用自己实现对LifecycleListener的管理和通知工作,而把工作统一交给LifecycleSupport处理。
图一是Tomcat组件生命周期管理的简要概述,组件一实现了Lifecycle接口,它通过LifecycSupport工具类管理它的监听者:一些实现了LifecycleListener的组件。当组件一需要通知组件二和组件三的时候,就将信息封装进LifecycleEvent中,由LifecycleSupport负责通知(调用其lifecycleEvent()方法):
对其中一些代码的解释:
Lifecycle接口中 addLifecycleListener()、removeLifecycleListener()用于增删监听者,当然它们的具体实现已经委托给LifecycleSupport去做了,start()、stop()方法用于组件的启动与关闭。
以上便是组件之间的通讯机制,接下来我们关注一下组件的生命周期,每个组件都有启动、运行、停止等主要活动。组件在启动的时候,势必要通知其下属组件、子组件,让它们先分别启动,最后组件本身才算启动完毕。图二中的左半部分说明了这个问题:每个组件,包括其下属组件和子组件都实现了Lifecycle接口,也就是说,父组件在start() 的时候会嵌套的调用其下属组件和子组件的start() 方法。这样就保证了组件启动的同时其子组件也会启动。同理,stop() 的方式也是一样的。由图二也可以更明确的看出Tomcat对LifecycleSupport和LifecycleEvent的重用。
图二,ContainerBase可能包含着它的子组件,比如Engine包含了Host,同时ContainerBase拥有一些下属组件,比如StandardPipeline、Logger、Cluser等:
我们可以重点看来看下ContainerBase的start()方法:
* Prepare for active use of the public methods of this Component.
*
* @exception LifecycleException if this component detects a fatal error
* that prevents it from being started
*/
public synchronized void start() throws LifecycleException ... {
// Validate and update our current component state
//这里是先验证当前组件是否已经启动
if (started) ...{
if(log.isInfoEnabled())
log.info(sm.getString("containerBase.alreadyStarted", logName()));
return;
}
// Notify our interested LifecycleListeners
//通知本组件的所有监听者,发出一个‘组件启动前事件’
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
//把组件标志为已经启动
started = true;
// Start our subordinate components, if any
//如果存在其下属组件,启动它们
//这里的下属组件可能是loader(ClassLoader)、logger(日志)、manager(Session管理)、
//cluster(集群)、realm(搞忘了Orz...)、resources(资源)等
if ((loader != null) && (loader instanceof Lifecycle))
((Lifecycle) loader).start();
logger = null;
getLogger();
if ((logger != null) && (logger instanceof Lifecycle))
((Lifecycle) logger).start();
if ((manager != null) && (manager instanceof Lifecycle))
((Lifecycle) manager).start();
if ((cluster != null) && (cluster instanceof Lifecycle))
((Lifecycle) cluster).start();
if ((realm != null) && (realm instanceof Lifecycle))
((Lifecycle) realm).start();
if ((resources != null) && (resources instanceof Lifecycle))
((Lifecycle) resources).start();
// Start our child containers, if any
//如果存在子组件、递归的启动它们
//子组件可能是Host、Context、Wrapper,一层包含一层
Container children[] = findChildren();
for (int i = 0; i < children.length; i++) ...{
if (children[i] instanceof Lifecycle)
((Lifecycle) children[i]).start();
}
// Start the Valves in our pipeline (including the basic), if any
//同样是启动下属组件,这里把Pipeline单独拿出来
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
// Notify our interested LifecycleListeners
//通知本组件的监听者,发出一个‘组件启动中事件’
lifecycle.fireLifecycleEvent(START_EVENT, null);
// Start our thread
//启动本Container的守护线程,每个容器都有自己的一个守护线程,用于定期做一些工作
//关于守护线程,我们后继文章再讨论
threadStart();
// Notify our interested LifecycleListeners
//通知组件的监听者,发出一个‘组件启动完毕事件’,至此本组件启动完毕
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}
Engine、Host、Context、Wrapper4个级别的容器都继承子ContainerBase,所以,它们的启动过程都是一样的,巧妙的达到了合理的复用^^