Tomcat的系统架构

Tomcat总体架构

Tomcat采用模块化设计,由外向内可以划分为:Server服务器模块,Service服务模块,Connector连接模块,Container容器模块。其中核心模块就是:Connector(连接器)和Container(容器)。一个Container可以选择对应多个Connector,多个Connector和一个Container就形成一个Service,有了Service就可以对外提供服务了。但是Service还需要一个生存的环境,必须能够给予其生命,掌控其生死大权,这就是Server了,所以整个Tomcat的生命周期由Server控制

实际上参看/conf/server.xml文件中的配置项层次结构就可以更为直观地理解这些模块/组件的包含关系

Service组件的作用

Service只是在Connector和Container外面多包一层,把它们组装在一起,向外面提供服务。一个Service可以设置多个Connector,但是只能有一个Container容器。实际上也就是为了关联Connector和Container,同时会初始化它下面的其他组件。

在Tomcat中Service接口的标准实现类是StandardService,它不仅仅实现了Service接口,同时还实现了Lifecycle接口(这个接口是控制组件的生命周期),这样它就可以控制下面组件的生命周期

在Service中存放Connector用的是数组,通过数组管理多个Connector

从Tomcat5开始,Service,Server和容器类都继承了MBeanRegistration接口,这样的管理更加统一合理

Server组件的作用

Server要完成的任务很简单,就是提供一个接口让其他程序能够访问到这个Service集合,同时要维护它所包含的所有Service的生命周期,包括如何初始化,如何结束服务,如何找到别人要访问的Service

它的标准实现类是StandardServer,这个类同时也实现了Lifecycle,MbeanRegistration两个接口的所有方法

Service和Server是互相关联的,Server也是和Service管理Connector一样管理它,也是将Service放在一个数组中,同时管理这个Service的生命周期

组件的生命周期Lifecycle

在Tomcat中组件的生命周期是通过LIfecycle接口来控制的,组件只需要实现这个接口里的方法就可以统一被拥有它的组件控制了。这样一层一层地直到最高级的组件就可以控制Tocmat中所有的生命周期了,这个最高级的组件就是Server,而控制Server的就是Startup和shutdown启动和关闭Tomcat

在Lifecycle接口中除了控制生命周期的start和stop方法外,还有一些方法用于监听,也就是在生命周期开始和结束时做一些额外的操作,这个监听机制在其他框架也有被使用,如Spring

Lifecycle接口的方法实现都在其他组件中,组件的生命周期由包含它的父组件控制,所以它的Start方法自然就是调用它下方组件的Start方法,Stop方法也是一样。如Server中Start方法就会调用Service组件的Start方法

Connector组件的作用

Connector组件作为Tomcat中的两大核心组件之一,它的主要任务是复负责接收浏览器发过来的Tcp连接请求,创建一个Request和Response对象分别用于和请求端交换数据。然后会产生一个线程来处理这个请求并把产生的Request和Response对象传给处理这个请求的线程,而处理这个请求的线程就是Container容器组件要做的事了

在Tomcat5中默认的Connector是Coyote,Connector最重要的就是接收连接请求,然后分配线程让Container来处理这个请求,所以必然是多线程的,多线程的处理是Connector设计的核心

当Connector将Socket连接封装成Request和Response对象后,接下来的事情就交给Container来处理了

Servlet容器Container

Container是容器的父接口,所有的子容器都必须实现这个接口,Container容器的设计用的是责任链的设计模式,它由4个子容器组件构成,分别是Engine,Host,Context和Wrapper,这4个组件不是平行的,而是父子关系,Engine包含Host,Host包含Context,Context包含Wrapper。通常一个Servlet class对应一个Wrapper,如果有多个Servlet,则可以定义多个Wrapper;如果有多个Wrapper,则要定义一个更高的Container,如Context,Context通常对应下面配置

/conf/server.xml:可以配置多个Context标签

<Context path="/app" docBase="D:\test\target\app.war" reloadable="true"/>

容器的总体设计

Context还可以配置到/conf/server.xml文件的父容器Host标签下,Host不是必须的,但是要运行war程序,就必须使用Host,因为在war中必然有web.xml文件,这个文件的解析就需要Host。如果要有多个Host就要定义一个top容器Engine。而Engine容器没有父容器了,一个Engine代表一个完整的Servlet引擎

从Tomcat5开始,子容器的路由就放在request对象中,所谓子容器的路由就是Context如何找到正确的Servlet并执行它,在request中保存了当前请求正在处理的Host,Context和Wrapper

Engine容器

Engine接口比较简单,它只定义一些基本的关联关系,它的标准实现类是StandardEngine,注意Engine没有父容器,如果调用setParent方法设置父容器会报异常,添加的子容器类型也只能是Host类型的

Host容器

Host是Engine的子容器,一个Host容器在Engine中代表一个虚拟主机,这个虚拟主机的作用是运行多个应用,它负责安装和卸载这些应用,并且标识这个应用以便能够区分它们,它的子容器是Context

在Tomcat中的实现类是StandardHost

Context容器

Context代表的就是Servlet中的Context,它具备了Servlet运行的基本环境,理论上只要有Context就能够运行Servlet了。Context最重要的功能就是管理它里面的Servlet实例,这些Servlet实例在Context中是以Wrapper出现的

Context是如何找到Servlet并运行它呢?就是上面说过的子容器的路由,获取子容器都是通过Request来的

Context的配置项中有个reloadable属性,当这个reloadable设为truewar被修改后Tomcat会自动重新加载这个应用。如何做到这一点呢?这个功能是在StandardContext类的backgroundProcess方法中实现的。这个方法会调用reload方法,而reload方法会先调用Start方法,然后调用Stop方法,完成Context的一次重新加载。那么这个backgroundProcess方法是怎么被调用的呢?这个方法是在ContainerBase类中定义的内部类ContainerBackgroundProcessor中被周期调用的,这个类运行在一个后台线程中。它会周期地执行run方法,它的run方法会周期地调用所有容器的backgroundProcess方法,因为所有容器都会继承COntainerBase类,所以所有容器都能够在backgroundProcss方法中定义周期执行的事件

Wrapper容器

Wrapper代表的就是一个Servlet,它负责管理一个Servlet,包括Servlet的装载,初始化,执行及资源回收。Wrapper是最底层的容器,它没有子容器了,所以调用它的addChild将会报异常

Wrapper的实现类是StandardWrapper,StandardWrapper还实现了拥有一个Servlet初始化信息的ServletConfig,由此看出StandardWrapper将直接和Servlet的各种信息打交道。StandardWrapper类有一个loadServlet方法,在这个方法中装载了Servlet就会调用Servlet的init方法,同时会传一个StandardWrapperFacade对象给Servlet,这个对象包装了StandardWrapper

Servlet可以获取的信息都在StandardWrapperFacade里封装,这些信息又是在StandardWrapper对象中拿到的,所以Servlet可以通过ServletConfig拿到有限的容器的信息,这里采用的是门面设计模式

当Servlet被初始化完成后,就等着StandardWrapperValue去调用它的Service方法了。调用Service方法之前要调用Servlet关联的所有Filter

posted @ 2021-02-15 14:21  OverZeal  阅读(146)  评论(0编辑  收藏  举报