前节回顾
通过上一节Tomcat架构设计概述我们知道Tomcat容器的整体架构,也都听过Tomcat的一键式启动模式,即当Catalina启动时,其包含的这些组件也会一起启动,同样,当Catalina关闭时,这些组件也都会随之关闭。
接下来,我们将会开始分析Tomcat是如何做到一键式启停的。
启动流程图
Tomcat的大致启动流程如下:
也许有人会疑问,怎么tomcat的启动流程跟我看到的有点不一样呢?Catalina不是调用的start()方法吗?怎么变成initInternal方法()了。其实呢这里我是省略了部分信息,只体现了启动过程中我觉得比较核心的过程。
还有为什么只有一个Container,没有Engine、Host、Context这些呢?为了体现简洁一点,可以理解为Container包含了所有类型的容器,所有容器都调用了这些方法(但提示一点Host并没有实现initInternal方法,但这不影响理解整个设计思想)
流程详解
由于上述的一个启动流程图只是描述了Tomcat中一键式启停的核心部分,其他的边缘的启动过程,可以详见下图:
由上图可知,其实在启动tomcat的时候我们是直接调用了Server的start()方法,那start方法是怎么变成调用initInternal()方法和startInternal()方法的呢?
首先Server的实例的类继承体系如下:
通过以上的类继承体系以及源码调用,可以知道从start至initInternal的整个调用过程如下:
tomcat设计上允许一个组件包含另一个组件,例如Server服务器可以包含多个Service服务,多个Listener等,所以tomcat设计由父组件负责启动/关闭它的子组件,这样就可以让所有的组件都置于其父组件的监护之下,也就意味着tomcat只需要启动一个组件就可以将全部的应用组件都启动起来。而这种单一启动/关闭机制就是通过Lifecycle接口实现的。
所以除了StandardServer之外,其他的所有继承LifecycleMBeanBase类在被相应的父组件调用时,都会相应的按照上述流程执行initInternal,startInternal。
Lifecycle接口
Lifecycle接口是所有组件实现生命周期管理的公共接口,提供的方法如下:
Lifecycle接口中最重要的就是start()和stop()方法,所有的组件都必须提供这两个方法的实现给其父组件调用,从而实现启动/关闭操作,而init方法是在执行start方法之前的一些准备工作。
其他的几个方法都是与事件监听有关的,每个组件都可以注册多个事件来对发生在该组件上的一些事件进行监听,当某个事件发生时,相应的事件监听器会收到通知。
除此之外,还有Lifecycle实例可以触发的事件。
LifecycleEvent
所有的生命周期事件都是LifecycleEvent类的实例。
LifecycleListener
生命周期的事件监听器是LifecycleListener接口的实例,该接口中只有一个方法,即lifecycleEvent()方法。当某个事件监听器监听到相关的事件发生时,就会调用该方法。
LifecycleSupport
tomcat提供的一个工具类,用来帮助组件管理监听器,并触发相应的生命周期事件。所以该类的方法主要就是对监听器做相关的操作,如添加、查找、删除监听器等。
监听器的调用
介绍了以上几种组件,那tomcat在启动时是怎么使用的呢?
首先在初始化每一个Lifecycle实例的时候,会在初始化LfiecycleBase时,将自身实例传给LifecycleSupport类。
然后在执行startInternal时,会调用fireLifecycleEvent方法。
最终调用LifecycleSupport类的fireLifecycleEvent()方法去找到该组件在该状态需要触发的监听器,并调用该监听器的lifecycleEvent()方法。
最终在完成整个启动操作后,tomcat启动流程完成,接下来便开始监听端口等待请求。
下节预告
此时根据结尾,大家会想到下一节,应该是讲tomcat是如何处理请求的吧。但是下节我将会先描述一下tomcat是如何摆脱硬编码,优雅的根据server.xml配置文件创建相应的容器实例的。算是一个小小的学习记录吧。