tomcat架构以及生命周期

时间:2020-11-27 08:58:32

    关于tomcat架构,之前一位前辈已经画得很清楚了,在众多tomcat架构图中,个人比较喜欢这副,因为这副图去繁留简,但是却又把精华的主*分留下来了。有兴趣可以一并看看参考文档中的这篇文章,这里引用这位前辈的图来补充讲一讲。

    tomcat架构以及生命周期

    当然,这幅图并没有勾勒出整体的框架以及他们之间的关系,有另一幅图表现了这个。

tomcat架构以及生命周期

    关于各个组件的讲解,请多多参考前辈的文章,本文中主要从整体关系和为什么这样设计来讲解这部分内容。

    最初从BootStrap开始启动,BootStrap会构造出最重要的3个ClassLoader的层级结构,引导加载Catalina这个核心类,并且接受外部的命令。

    而Catalina执行的最重要的任务就是在load方法中用digest将conf/server.xml这个配置文件解析并且组装好里面的组件,这一组装过程严格按照digest的rule来进行。而Catalina会进一步分解Bootstrap命令所调用的API。为什么要有Catalina呢,之前已经提过了,Catalina最主要的作用就是装配好了整个骨架,就像上帝造人,也得先造骨架,后面的肌肉皮肤才能依存其上。

    Catalina将骨架搭好之后,就开始点火启动Server,Server在整个服务器中是一个最大的概念,所有的组件都在其下,也就是说,如果我们想要操作服务器,例如关闭,有种方式是将其他所有的组件一个一个关闭,但是有了server之后,只需要关闭server,他会负责关闭下面的所有组件,类似于一个打包的概念。在server中,可以通过配置指定关闭的端口和命令。

    一个Server,其下可以定义一个或者多个Service,每个service其实上就是一种类型的web服务,他包括一个和多个Connector以及一个Engine。很多人奇怪为什么Server需要提供多个Service,其实这里大有用处,比如我们tomcat配置两个Service,当apache在前端服务,后端的tomcat中其中一个服务用于接收apache的请求,而另一个服务则用于自己本身对外界提供jsp服务;又或者我们需要扩展,其中一个service提供jsp服务,另一个则提供ftp下载服务(当然不会这么做了,但是因为service,所以我们有了更加灵活的可能性,比如哪天你发明了一种协议,那么可以加一个service用于处理这种协议或者这个服务)。所以service能够扩展我们的服务种类。Service是一个联姻结构,他让Engine和Connector得到结合(有篇文章这么比喻的,感觉很形象,我赞同Engine是男人tomcat架构以及生命周期),这里可以看出tomcat的高度模块化,从功能上来说,Connector的存在有其特殊的意义,因为不同的Connector可以负责不同的协议,监听不同的端口,做不同的解析,而Engine则是实际做事的发动机,具体职责是有区分的。

    Connector是一个抽象的组件,会根据配置来决定装配哪些Connector,Connector对应的协议,端口等信息。另外,Connector对象还保存了一些对参数限制的常数,比如最大参数数量(默认10000),最大的POST大小(默认2M,事实上,POST已经属于协议的范畴了,按理应该放在Http11Protocol中,但是这里由于调用者封装性不能轻易的拿到Http11Protocol,故放到了Connector)。所以,如果你需要自己设计一个Connector这样的组件,应该也是有思路的。

    接下来就是Container,Container这个结构比较复杂,图上也能看出来,他包含了很多对象。首先,我们来看继承自他的子类,container只有四种,分别是Engine, Host, Context和Wrapper,他们分别构成了一个执行的层次。其次,另一组结构是Pipeline和Valve,有他们代表的就是对执行流的过滤和处理过程。最后,是Loader,用来重新加载(比如热部署),Manager(用来对session控制)以及Realm(安全)。之后我们分别讲解每一个组件。但是首先,让我们来看看,为什么这个层次结构要这样设计,

    Engine,就是tomcat处理请求的引擎,类似于汽车发动机的核心地位,很多人觉得,为什么tomcat不应该是一个引擎就能让系统运转下去了吗,让他在service之下,岂不是可以有多个引擎了。的确,在正常的汽车中只有一个引擎,但是不排除他有多个引擎的可能性,想想看,特殊跑车,飞机,甚至是合金装备,都可能会有多个引擎。那么,Engine这个元素在这里有什么用呢,首先,他是Host的上级元素,因为有他存在,所以可以方便的触发并操作所有Host;其次,Engine中记录了Cluster时的jvmRouteId(想想看,为什么这个jvmRouteId不定义在Service?),这样,集群环境下,tomcat才能够互相标示

    Host,大家都解释为虚拟主机,那么,在实际应用中虚拟主机到底有什么用呢?由于Connector是跟Engine一起放在Service中的,如果要复用Connector,只能往Engine下层走,即Host。Host的源码注释中给出了另一个应用的例子,即基于host的拦截器可以拦截到该虚拟主机的所有request,而不是其他的host的,这里我猜想一下拦截器的实现可以用valve来做。关于Host的更多解释,可以参考第二第三篇文档。

    Context,这里的组件特指webapp的运行上下文,如何理解这个context呢?比如应用叫做firework,那么http://www.xxx.xxx/firework这个context就是特指firework这个应用。

    Pipeline,管道,之所有它的概念,是因为pipeline是用来更清晰的装配Valve的。可以这样比喻,pipeline就像一条水管,request则是水管中流的水,而Valve则是水管上的一排水龙头。

    Valve,用于处理管道的过滤操作,而管道存在于Engine, Host, Context中,所以Valve可以过滤各个级别发来的请求。

    Realm,用于安全控制。主要是用来对用户输入的用户名和密码进行有效性判断。

    Loader,应用程序载入器,主要是用于做tomcat中一些定制化的类加载方式,loader负责管理加载的一些复杂的设置,而真正实现定制化类加载的,则是WebAppClassLoader。


    tomcat的生命周期实际上是一个比较经典的模式,对于大型项目的架构通常可以参考,所有的tomcat容器(四大容器包括:Engine, Host, Context, Wrapper)都直接或间接继承了Lifecycle接口,另外,上面的所有组件都无一例外的继承了该接口。这个接口主要对外提供了两个方法,即start和stop,为什么这么重要?因为所有组件都可以被外面启停了,而且都是采用事件的方式通知到所有关注启停事件的类。这里可以看到经典的解耦方式,即观察者模式,被关注者不需要关心关注者到底是谁,也不需要在需要被关注时去手动通知关注者,取而代之,这个过程被LifecycleSupport这个类实现,LifecycleSupport帮助被关注者管理所有的关注着,并且在触发事件时负责通知所有关注者,这意味着它屏蔽了通知的细节,解放了被关注者。为什么这里不用java中经典的Observer和Observable呢?一方面是Observable需要继承,万一client还需要继承其他父类呢?所以改用复合关系更加漂亮;另一方面是Observer的接口名叫update,天知道update是用来干嘛的。

    tomcat架构以及生命周期

    参考文档:http://blog.csdn.net/cutesource/article/details/5006062

http://www.goldendoc.org/2011/02/tomcat_host/

http://ssh-2009-126-com.iteye.com/blog/1068095