总体架构
Tomcat最顶层的容器是Server,代表着整个服务,控制着整个Tomcat的生命周期。一个Server可以包含至少一个Service,用于具体提供服务。
Service主要包含两个部分:Connector和Container。从上图中可以看出 Tomcat 的心脏就是这两个组件,他们的作用如下:
- Connector用于处理连接相关的事情,并提供Socket与Request和Response相关的转化;
- Container用于封装和管理Servlet,以及具体处理Request请求;
一个Service只有一个Container,但是可以有多个Connectors,这是因为一个服务可以有多个连接,如同时提供Http和Https链接。
另外,上述的包含关系或者说是父子关系,都可以在tomcat的conf目录下的server.xml配置文件中看出,下图是删除了注释内容之后的一个完整的server.xml配置文件(Tomcat版本为8.5)
<?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" />
<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="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>
Connector和Container的关系
一个请求到达Tomcat之后,首先经过Service然后会交给Connector,Connector用于接收请求并将请求封装为Request和Response来具体处理,Request和Response封装完之后交给Container处理,Container处理完之后再交给Connector,最后由Connector通过Socket将处理结果返回给客户端。
Connector最底层使用Socket来进行连接,Request和Response是按照HTTP协议来封装的,所以Connector需要同时实现TCP/IP协议和HTTP协议。
Connector 架构分析
Connector用于接收请求并将请求封装为Request和Response,然后交给Container处理,处理完之后再由Connector返回给客户端。因此可以把Connector分解为四个方面进行理解:
- Connector如何接收请求的?
- Connector如何将请求封装为Request和Response的?
- 封装完之后的Request和Response是如何交给Container处理的?
- Container处理完之后如何交给Connector返回给用户的?
Connector的结构图
Connector就是使用ProtocolHandler来处理请求的,不同的ProtocolHandler代表不同的连接类型,如Http11Protocol使用普通的Socket来连接的,Http11NioProtocol使用的NioSocket来连接。
ProtocolHandler包含了三个部件:Endpoint、Processor、Adapter
- EndPoint用来处理底层的Socket网络连接,Processor用于将接收到的Socket封装成Request,Adapter用于将Request交给Container具体处理。
- Endpoint由于是处理底层的Socket网络连接的,所以Endpoint是用来实现TCP/IP协议的,而Processor是用来实现HTTP协议的,Adaper用来将请求适配到Servlet容器进行处理的。
- Endpoint的抽象实现AbstractEndpoint里面定义的Acceptor和AsyncTimeout两个内部类和一个Handler接口。Acceptor用于监听请求,AsyncTimeout用于检查异步Request的超时,Handler用于处理接收到的Socket,在内部调用Processor进行处理。
Container架构分析
Container用于封装和管理Servlet,以及具体处理Request,在Container内部包含了四个子容器,结构如下:
四个子容器分别是:
- Engine:引擎,用来管理过个站点,一个Service最多只能有一个Engine
- Host:代表一个站点,也可以叫做虚拟主机,通过配置Host可以添加站点
- Context:代表着一个应用,或者一个WEB-INF目录下以及下面的web.xml文件
- Wrapper:Wrapper封装着一个Serlvet
Context和Host的区别是Context代表着一个应用,tomcat中默认的配置下webapp下的每一个文件夹目录都是一个Context,其中ROOT放着主应用,其他放着子应用,而这个webapp代表着一个Host站点。
Container如何处理请求的?
Container处理请求使用的是Pipeline-Valve管道来处理的
Pipeline-Valve是责任链模式,责任链模式是指一个请求处理过程中有很多处理者依次对请求进行处理,每一个处理者负责做自己相应的处理,处理完之后将请求返回,再让下一个处理者继续处理。
Pipeline-Valve使用的责任链和普通的责任链有些不同,有两点区别
- 每个pipeline都有特定的valve,而且是在管道的最后一个执行,这个valve叫做BaseValve,BaseValve是不可删除的
- 上层容器的管道的BaseValve中会调用下层容器的管道
Pipeline处理的流程:
Connector接收到请求之后首先调用顶层容器的Pipeline来处理,也就是EnginePipeline,然后再依次调用Host的管道、Context的管道和Wrapper的管道,最后执行到StandardWrapperValve。当执行到standardWrapperValve的时候,会在standardWrapperValve中创建FilterChain,并调用doFilter来处理请求,这个FilterChain中包含中配置的与请求相匹配的Filter和Servlet,其中doFilter调用所有的Filter的doFilter和Servlet方法的Service方法。当所有的Pipeline-valve都执行完之后,并处理完具体的请求,然后将处理的结果交给Connector,Connector再通过Socket的方式将结果返回给客户端。
Tomcat中的组件分析
- Server
Server默认实现是StandarServer,提供了findService、getCatalina、getCatalinaHome、getCatalinaBase等接口,支持查找、遍历Service组件,这里似乎看到了和Serivce组件的些许联系
public interface Server extends Lifecycle {
public NamingResourcesImpl getGlobalNamingResources();
public void setGlobalNamingResources(NamingResourcesImpl globalNamingResources);
public javax.naming.Context getGlobalNamingContext();
public int getPort();
public void setPort(int port);
public String getAddress();
public void setAddress(String address);
public String getShutdown();
public void setShutdown(String shutdown);
public ClassLoader getParentClassLoader();
public void setParentClassLoader(ClassLoader parent);
public Catalina getCatalina();
public void setCatalina(Catalina catalina);
public File getCatalinaBase();
public void setCatalinaBase(File catalinaBase);
public File getCatalinaHome();
public void setCatalinaHome(File catalinaHome);
public void await();
public Service findService(String name);
public Service[] findServices();
public void removeService(Service service);
public Object getNamingToken();
}
- Service
Service的默认实现类是StardardService,类结构和StardardServer很相似,也是继承至LifecycleMBeanBase,实现了Service接口
由Service接口不难发现Service组件的内部结构
- 持有Engine实例
- 持有Server实例
- 可以管理多个Connector实例
- 持有Executor引用
public class StandardService extends LifecycleMBeanBase implements Service {
// 省略若干代码
}
public interface Service extends Lifecycle {
public Engine getContainer();
public void setContainer(Engine engine);
public String getName();
public void setName(String name);
public Server getServer();
public void setServer(Server server);
public ClassLoader getParentClassLoader();
public void setParentClassLoader(ClassLoader parent);
public String getDomain();
public void addConnector(Connector connector);
public Connector[] findConnectors();
public void removeConnector(Connector connector);
public void addExecutor(Executor ex);
public Executor[] findExecutors();
public Executor getExecutor(String name);
public void removeExecutor(Executor ex);
Mapper getMapper();
}
- Connector
Connector是tomcat中监听TCP端口的组件,server.xml默认定义了两个Connector,分别用于监听http、ajp端口。对应的代码是org.apache.catalina.connector.Connector,它是一个实现类,并且实现了Lifecycle接口
- http
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
http对应的Connector配置如上所示,其中protocol用于指定http协议的版本,还可以支持2.0;connectionTimeout定义了连接超时时间,单位是毫秒;redirectPort是SSL的重定向端口,它会把请求重定向到8443这个端口
- AJP
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
Apache jserver协议(AJP)是一种二进制协议,它可以将来自web服务器的入站请求发送到位于web服务器后的应用服务器。如果我们希望把Tomcat集成到现有的(或新的)Apache http server中,并且希望Apache能够处理web应用程序中包含的静态内容,或者使用Apache的SSL处理,我们便可以使用该协议。但是,在实际的项目应用中,AJP协议并不常用,大多数应用场景会使用nginx+tomcat实现负载。
- Container
org.apache.catalina.Container接口定义了容器的api,它是一个处理用户servlet请求并返回对象给web用户的模块,它有四种不同的容器:
- Engine,表示整个Catalina的servlet引擎
- Host,表示一个拥有若干个Context的虚拟主机
- Context,表示一个Web应用,一个context包含一个或多个wrapper
- Wrapper,表示一个独立的servlet
Engine、Host、Context、Wrapper都有一个默认的实现类StandardXXX,均继承至ContainerBase。此外,一个容器还包含一系列的Lodder、Logger、Manager、Realm和Resources等
一个容器可以有一个或多个低层次上的子容器,并且一个Catalina功能部署并不一定需要全部四种容器。一个Context有一个或多个wrapper,而wrapper作为容器层次中的最底层,不能包含子容器。
代码模块简介
catalina包
Tomcat的核心模块,包括了HttpServlet、HttpSession的实现,以及各大组件的实现,这块的代码量是最多的,也是最复杂的一部分
coyote包
这块主要用于支持各种协议,比如http1.1、http2.0、ajp等,代码量较少
tomcat包
tomcat的基础包,包括了数据库连接池、websocket实现、tomcate的jni、工具类。org.apache.tomcat.util包的代码量也不少,其中还包括了对jdk源码的扩展,比如线程池。
参考:
https://blog.csdn.net/xlgen157387/article/details/79006434
https://blog.csdn.net/Dwade_mia/article/details/79051404