Tomcat是什么?
Tomcat 服务器是一个基于Java语言开发的,免费的开放源代码的Web应用服务器,属于轻量级应用服务器。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web应用服务器。
本文所述版本:8.5.50
从整体看Tomcat
Tomcat整体结构图
先从整体上认识Tomcat内部的架构层次。如果将Tomcat内核高度抽象,则它可以看成由连接器(Connector)组件和容器(Container)组件组成。
- Connector组件(也可以叫Coyote,Coyote是Connector框架的名字)负责在服务器端处理客户端连接,包括接收客户端连接、接收客户端的消息报文以及消息报文的解析等工作。
- Container组件则负责对客户端的请求进行逻辑处理,并把结果返回给客户端。
Container组件在图中并不能找到,它其实包括4个级别的容器:Engine组件、Host组件、Context组件和Wrapper组件,Container也是整个Tomcat的核心。
从Tomcat服务器配置文件server.xml的内容格式看,它所描述的Tomcat也符合上图的层级结构,所以从server.xml文件也能看出Tomcat的大体结构,servlet配置文件参考图:
各组件介绍
Catalina
负责解析Tomcat的配置文件(server.xml) , 以此来创建服务器Server组件并进行管理。
Server
Server是最顶级的组件,它代表Tomcat的运行实例,在一个JVM中只会包含一个Server。负责组装并启动Servlet引擎。Server通过实现Lifecycle接口,提供了一种优雅的启动和关闭整个系统的方式。在Server的整个生命周期中,不同阶段会有不同的事情要完成。为了方便扩展,它引入了监听器方式,所以它也包含了Listener组件。另外,为了方便在Tomcat中集成JNDI,引入了GlobalNamingResources组件。
Service
Service在设计上Server组件可以包含多个Service组件,每个Service组件都包含了若干用于接收客户端消息的Connector组件和处理请求的Engine组件。不同的Connector组件使用不同的通信协议,如HTTP协议和AJP协议,当然还可以有其他的协议A和协议B。若干Connector组件和一个客户端请求处理组件Engine组成的集合即为Service。此外,Service组件还包含了若干Executor组件,每个Executor都是一个线程池,它可以为Service内所有组件提供线程池执行任务。它将若干个Connector组件绑定到一个 Container。
Connector(Coyote)
Coyote(Coyote是Connector框架的名字) 是Tomcat 中连接器的组件名称 , 是对外的接口。客户端通过Coyote与服务器建立连接、发送请求并接收响应 。
-
Coyote 封装了底层的网络通信(Socket 请求及响应处理)
-
Coyote 使Catalina 容器(容器组件)与具体的请求协议及IO操作方式完全解耦
-
Coyote 将Socket 输入转换封装为 Request 对象,进一步封装后交由Catalina 容器进行处理,处理请求完成后, Catalina 通过Coyote 提供的Response 对象将结果写入输出流
-
Coyote 负责的是具体协议(应用层)和IO(传输层)相关内容
Tomcat支持多种应用层协议和I/O模型,如下:
应用层协议:
应用层协议 | 描述 |
---|---|
HTTP/1.1 | 大部分为web应用采用的访问协议。 |
AJP | 用户和WX集成(如Apache),以实现对静态资源的优化以及集群部署,当前支持AJP/1.3 |
HTTP/2.0 | HTTP/2.0大幅度提升web性能。下一代HTTP协议,自8.9/9.0版本后开始支持 |
I/O模型:
IO模型 | 描述 |
---|---|
NIO | 非阻塞I/O,采用Java NIO类库实现。 |
NIO2 | 异步I/O,采用JDK7最新的NIO2类库实现。 |
APR | 采用Apache可移植运行库实现,是C/C++编写的本地库。如选择此方案,需要单独安装APR库 |
NIO Connector结构
Coyote的内部组件及流程
EndPoint
EndPoint 是 Coyote 通信端点,即通信监听的接口,是具体Socket接收和发送处理器,是对传输层的抽象,因此EndPoint用来实现TCP/IP协议的。
ProtocolHandler
Coyote 协议接口, 通过Endpoint 和 Processor , 实现针对具体协议的处 理能力。Tomcat 按照协议和I/O 提供了6个实现类 : AjpNioProtocol , AjpAprProtocol, AjpNio2Protocol , Http11NioProtocol , Http11Nio2Protocol ,Http11AprProtocol
Processor
Processor 是Coyote 协议处理接口 ,如果说EndPoint是用来实现TCP/IP协 议的,那么Processor用来实现HTTP协议,Processor接收来自EndPoint的 Socket,读取字节流解析成Tomcat Request和Response对象,并通过 Adapter将其提交到容器处理,Processor是对应用层协议的抽象
Adapter
由于协议不同,客户端发过来的请求信息也不尽相同,Tomcat定义了自己的 Request类来封装这些请求信息。ProtocolHandler接口负责解析请求并生成 Tomcat Request类。但是这个Request对象不是标准的ServletRequest,不 能用Tomcat Request作为参数来调用容器。Tomcat设计者的解决方案是引 入CoyoteAdapter,这是适配器模式的经典运用,连接器调用 CoyoteAdapter的Sevice方法,传入的是Tomcat Request对象, CoyoteAdapter负责将Tomcat Request转成ServletRequest,再调用容器
Container
Container组件下有几种具体的组件,分别是Engine、Host、Context和Wrapper。这4种组件(容器)是父子关系。Tomcat通过一种分层的架构,使得Servlet容器具有很好的灵活性。
Engine
Engine表示整个Catalina的Servlet引擎,用来管理多个虚拟站点,每个Service组件只能包含一个Engine容器组件, 但Engine组件可以包含若干Host容器组件。
Host
代表一个虚拟主机,或者说一个站点,可以给Tomcat配置多个虚拟主机地址,而一个虚拟主机下可包含多个Context。
Context
表示一个Web应用程序, 一个Web应用可包含多个Wrapper。
Wrapper
表示一个Servlet,Wrapper 作为容器中的最底层,不能包含子容器。
Tomcat启动时序图
启动脚本在mac下是startup.sh,在windows下是startup.bat。
init初始化调用栈:
Start启动调用栈:
Tomcat8.5.50默认使用NIO:
请求处理的整体过程
整体看一下客户端从发起请求到响应的整个过程在Tomcat内部如何流转。
处理细节
下面介绍请求流转的具体过程(主流程):
- 当Tomcat 启动后,Connector组件的接收器(Acceptor)将会监听是否有客户端套接字连接并接收Socket。
- 一旦监听到客户端连接,则将连接交由线程池Executor处理,开始执行请求响应任务。
- Http11NioProcessor组件负责从客户端连接中读取消息报文,然后开始解析HTTP的请求行、请求头部、请求体。将解析后的报文封装成Request对象,方便后面处理时通过Request对象获取HTTP协议的相关值。
- Mapper组件根据HTTP协议请求行的URL属性值和请求头部的Host属性值匹配由哪个Host容器、哪个Context容器、哪个Wrapper容器处理请求,这个过程其实就是根据请求从Tomcat中找到对应的Servlet。然后将路由的结果封装到Request对象中,方便后面处理时通过Request对象选择容器。
- CoyoteAdaptor组件负责将Connector组件和Engine容器连接起来,把前面处理过程中生成的请求对Request和响应对象Response传递到Engine容器,调用它的管道。
- Engine容器的管道开始处理请求,管道里包含若干阀门(Valve),每个阀门负责某些处理逻辑。可以根据自己的需要往这个管道中添加多个阀门,它会负责匹配并调用Host容器的管道。
- Host容器的管道开始处理请求,它同样也包含若干阀门(Valve),它继续往下调用匹配Context容器的管道。
- Context容器的管道开始处理请求,它负责调用Wrapper容器的管道。
- Wrapper容器的管道开始处理请求,它会执行该Wrapper容器对应的Servlet对象的处理方法,对请求进行逻辑处理,并将结果输出到客户端。