参考文章:
《Tomcat架构解析》刘光瑞著
写在开头:本文为学习后的总结,可能有不到位的地方,错误的地方,欢迎各位指正。
一、tomcat的基本结构
一、连接器(connect)与容器(containor)
在tomcat中,为了实现功能的解耦,将开启socket并监听客户端请求、返回数据的功能与具体的请求处理进行了拆分,这两者分别是连接器connect和容器containor,一个server可以拥有多个connect和containor。
1、Coyote
coyote是tomcat链接器的框架,对于不同的网络协议与I/O方式提供了不同的处理方案。
在coyote中,由以下几个核心概念
(1)Endpoint:coyote的通信端点,是具体的socket的接受处理类。不过tomcat中并没有Endpoint接口,而是提供了一个抽象类AbstractEndpoint。根据不同的I/O方式,提供了NioEndpoint、AprEdnpoint、Nio2Endpoint等实现方式。
(2)Processor:coyote的协议处理接口,负责构造request和response对象,并通过Adapter将其提交给containor,是对应用层的抽象。Processor是单线程的,tomcat在同一次链接中复用Processor。tomcat为Processor提供了3个实现类:Http11Procesor(HTTP/1.1)、AjpProcessor(AJP)、StreamProcessor(HTTP/2.0)。
(3)ProtocolHandler:coyote协议接口,通过封装Endpoint和Processor。实现对具体协议的处理功能。tomcat按照网络协议和I/O方式提供了6个实现类,包括Http11NioProtocol、Http11AprProtocol、Http11Nio2Protocol等。
2、containor
在容器中,如同套娃一样,由最外层的Engine包含了多个Host,每个Host又可以对应多个Context,每个Context又可以包含多个Wrapper。
我们首先来看下专业性的说明:
(1)Engine:用于从connector组件处接收已建立的TCP连接,还用于接收客户端发送的http请求并分析请求,然后按照分析的结果将相关参数传递给匹配出的虚拟主机。engine还用于指定默认的虚拟主机。
个人解读:一组域名的集合,默认域名是localhost。
(2)Host:容器定义虚拟主机,由于tomcat主要是作为servlet容器的,所以为每个webapp指定了它们的根目录appBase。
个人解读:每一个host可以拥有1个不同的域名,不同的应用部署地址。
(3)Context:容器主要是根据path和docBase获取一些信息,将结果交给其内的wrapper组件进行处理(它提供wrapper运行的环境,所以它叫上下文context)。一般来说,都采用默认的标准wrapper类,因此在context容器中几乎不会出现wrapper组件。
个人解读:每一个context对应部署的每一个具体应用。
(4)Wrapper:容器对应servlet的处理过程。它开启servlet的生命周期,根据context给出的信息以及解析web.xml中的映射关系,负责装载相关的类,初始化servlet对象init()、执行servlet代码service()以及服务结束时servlet对象的销毁destory()。
个人解读:代表每一个具体的servlet,可以理解为1个后台。
3、整体结构
我们可以很清楚的看出,1个server包含多个service,1个service又包含多个connect和1个container。这个在我们接下来解读server.xml时会有所帮助。
二、servel.xml的结构
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" enableLookups="false" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase" />
</Realm>
<Host name="www.longshuai.com" appBase="/www/longshuai"
unpackWARs="true" autoDeploy="true">
<Context path="" docBase="/www/longshuai" reloadable="true" />
<Context path="/xuexi" docBase="xuexi" reloadable="true" />
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="longshuai_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
<Host name="www.xiaofang.com" appBase="webapps/xiaofang"
unpackWARs="true" autoDeploy="true">
<Context path="" docBase="" reloadable="true" />
<Context path="/xuexi" docBase="xuexi" reloadable="true" />
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="xiaofang_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
原文《Tomcat(二):tomcat配置文件server.xml详解和部署简介》
以上面的xml为例,我们结合第一节中的tomcat结构来解读。
1、Service
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" enableLookups="false" />
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
我们可以看到,service下有2个connect。1个对应8080端口,接受http1.1协议。超时时间20s。另一个对应8009端口,接受ajp协议。
因此可以得出这样的结论,service是1组connect和1个container的结合。
2、Host
<Host name="www.longshuai.com" appBase="/www/longshuai"
unpackWARs="true" autoDeploy="true">
<Context path="" docBase="/www/longshuai" reloadable="true" />
<Context path="/xuexi" docBase="xuexi" reloadable="true" />
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="longshuai_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
<Host name="www.xiaofang.com" appBase="webapps/xiaofang"
unpackWARs="true" autoDeploy="true">
<Context path="" docBase="" reloadable="true" />
<Context path="/xuexi" docBase="xuexi" reloadable="true" />
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="xiaofang_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
在同一个Engine下,包含了3个Host,分别对应localhost、www.xiaofang.com、www.longshuai.com这三个域名,appBase节点则代表了应用的部署目录。
3. Context
个性化修改Host默认web应用的路径。比如上文中的4个应用对应的访问地址分别为www.longshuai.com:8080、www.longshuai.com:8080/xuexi、www.xiaofang.com:8080、www.xiaofang.com:8080/xuexi。这里端口为8080的原因为,我们在上文中connect的配置为
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" enableLookups="false" />