从实现类来看,Tomcat的连接器主要支持两种协议:HTTP/1.1
协议和AJP
协议,实则还支持HTTP/2.0
协议,HTTP/2.0
的处理与HTTP/1.1
和AJP
不同,采用一种升级协议的方式实现。
-
HTTP/1.1
协议:大家最熟悉的协议了,绝大多数web应用采用的访问协议,Tomcat既是Servlet
容器又是HTTP服务器,单独运行就可以对外提供服务,但是一般会搭配Nginx
web服务器做反向代理和负载均衡。 -
HTTP/2.0
协议:自Tomcat8.5开始支持,相较于HTTP/1.1
采用二进制传输数据而非文本格式;对消息头采用HPACK
压缩,提升传输效率;基于帧和流的多路复用,真正实现了基于一个连接多请求并发处理;支持服务器主动推送。 -
AJP/1.3
协议:全名Apache JServ Protocol,是Alexei Kosut创建的定向包通信协议,采用二进制格式传输可读文本。用于集成Web服务器,以提升静态资源的访问性能,当前最新版本为1.3。目前Apache
、Tomcat
、Nginx
、Jetty
、JBoss
等均已支持AJP
。(名不见经传,不过多解释)
除了支持3种协议外,还分别支持3种I/O方式:NIO
、NIO2
、APR
,Tomcat8.5之前默认还支持BIO
,后来因为性能问题直接给删除了,APR也贴上了过期标签。协议和I/O方式两两组合就出现了很多实现类:Http11NioProtocol
、Http11Nio2Protocol
、Http11AprProtocol
(已过期)、AjpNioProtocol
、AjpNio2Protocol
、AjpAjpProtocol
(已过期)。(HTTP/2.0
是在HTTP/1.1
的基础上升级处理的,不在该继承体系内,APR
采用Apache
可移植运行库(c++
编写的本地库,就是native
方法)实现的,官方已标注过期不建议使用,所以不过多解释)
Tomcat采用UpgradeProtocol
表示HTTP升级协议,当前只有一个实现类Http2Protocol
用于处理HTTP/2.0
。它根据请求创建一个用于升级处理的令牌UpgradeToken
,该令牌包含了具体的HTTP升级处理器HttpUpgradeHandler
(HTTP/2.0
的处理器为Http2UpgradeHandler
)。(Tomcat中WebSocket
也是通过UpgradeToken
机制实现的,其处理器为WsHttpUpgradeHandler
)
1、Endpoint通信端点
Endpoint
负责网络通信,监听一个端口,循环接收socket
请求,读取网络字节流等。Endpoint
不是接口,而是提供了一个抽象类AbstractEndpoint
,又根据I/O方式提供了若干实现类:
网络通信这一层是非常抽象的,传输层协议毋庸置疑是TCP/IP
,但是如何监听socket请求,读取网络字节流的方式是多样的,同步非阻塞、I/O多路复用、异步非阻塞等等:
-
Endpoint
高度抽象出一个Acceptor
来循环监听socket
请求; -
Tomcat是支持高并发的,但是机器的性能是有限的,为了保证Web服务器不被高流量冲垮,所以在接收请求前会有一个
LimitLatch
限流器(利用AQS
实现); -
接收到的
socket
通道(SocketChannel
orAsynchronousSocketChannel
),会先根据I/O方式包装一下,如同步非阻塞NioChannel
、异步非阻塞Nio2Channel
等; -
包装之后的
socket
通道又用一个更抽象的SocketWrapper
封装,以应对不同方式的网络字节流的读取和写入; -
出于高并发的设计,将抽象的
SocketWrapper
交由SocketProcessor
任务对象处理,SocketProcessor
会扔进一个线程池Executor
处理; -
为了进一步提高性能,每次处理请求都会把一些对象缓存起来,不重复创建,比如
SocketWrapper
、SocketProcessor
等。
2、Processor应用层协议解析
Acceptor
接收到请求封装成一个SocketProcessor
扔进线程池Executor
后,会调用Processor
从操作系统底层读取、过滤字节流,对应用层协议(HTTP/AJP
)进行解析封装,生成org.apache.coyote.Request
和org.apache.coyote.Response
对象。不同的协议有不同的Processor
,HTTP/1.1
对应Http11Processor
,AJP
对应AjpProcessor
,HTTP/1.2
对应StreamProcessor
,UpgradeProcessorInternal
和 UpgradeProcessorExternal
用于协议升级:
(1)ConnectionHandler创建合适的Processor
SocketProcessor
并不是直接调用的Processor
,而是通过org.apache.coyote.AbstractProtocol.ConnectionHandler#process
找到一个合适的Processor
进行请求处理:
-
根据不同协议创建
Http11Processor
orAjpProcessor
; -
根据协议升级是内部升级(
HTTP/2.0
)还是外部升级创建UpgradeProcessorInternal
orUpgradeProcessorExternal
。
(2)协议升级
如果是正常的协议,如HTTP/1.1
、AJP/1.3
,则Processor#process
处理完请求后会直接调用Adapter#service
,将请求转发给Container
。
如果是协议升级(除Websocket
),首先通过HTTP/1.1进行协议升级:
-
服务器接收到带有特殊请求头(
Upgrade
)的HTPP/1.1
连接,因此仍会先交给Http11Processor
进行处理; -
根据请求头
Upgrade
对应协议名创建UpgradeToken
,并赋值给当前Processor
; -
返回
SocketState.UPGRADING
,再由ConnectionHandler
进行协议升级; -
ConnectionHandler
会从当前Processor
获取UpgradeToken
对象(如果没有,则默认为HTTP/2.0),并构建一个升级的Processer
(若为Tomcat可以处理的协议升级(HTTP/2.0
、WebSocket
) ,则是UpgradeProcessorInternal
,否则为UpgradeProcessorExternal
)。 -
替换当前
Processer
,并将当前Processer
释放回收; -
将
UpgradeProcessor
设置给UpgradeToken
中的HttpUpgradeHandler
,并调用HttpUpgradeHandler.init
进行初始化,开启升级协议的处理。 -
由于
HTTP/2.0
是多路复用协议,一个连接可以处理多个HTTP请求,所以对于Http2UpgradeHandler
,会将每次请求响应交于StreamProcessor
处理,再由StreamProcessor
将请求提交给Container
。
注意:
-
UpgradeProcessorInternal
和UpgradeProcessorExternal
都实现了接口WebConnection
,表示一个用于升级的连接,并不处理协议升级后数据读写和解析,而是交由HttpUpgradeHandler
,对于Http2UpgradeHandler
再构建StreamProcessor
,又将StreamProcessor
包装成任务类StreamRunnable
,扔进线程池Executor
处理。 -
WebSocket
也属于协议升级,和HTTP/2.0
升级方案一致,但是协议升级的判断机制有所不同,WebSocket
升级判断不在连接器里,而是交由Servlet
容器通过当前请求的过滤器WsFilter
判断,如果是WebSocket
协议升级,则调用当前org.apache.catalina.connector.Request#upgrade
构建UpgradeToken
并传递给Http11Processor
处理(调用钩子函数org.apache.coyote.AbstractProcessor#action
),之后到了ConnectionHandler
逻辑就跟HTTP/2.0
升级差不多了。
3、配置方式
<Connector port=“8080” protocol=“HTTP/1.1”
connectionTimeout=“20000”
executor=“tomcatThreadPool”
redirectPort=“8443”>
-
port
是Connector
监听的端口。 -
protocol
是应用层协议名,可填参数有HTTP/1.1
、org.apache.coyote.http11.Http11NioProtocol
、AJP/1.3
、org.apache.coyote.ajp.AjpNioProtocol
,如果protocol
不填,则默认为Http11NioProtocol
。 -
connectionTimeout
表示Connector
接收到连接后等待超时时间,单位毫秒,默认20秒。 -
executor
表示使用一个共享线程池,若使用私有线程池,则executor
不需要指定,私有线程池可选参数有minSpareThreads=“10”
、maxThreads=“200”
等 -
redirectPort
表示非SSL
重定向到SSL
端口,当请求是non-SSL
请求,但是接收到的请求内容需要SSL
传输,则重定向到SSL
端口。 -
若为
HTTP
开启HTTP/2.0
支持,需要配置UpgradeProtocol
。
Adapter
接口只有一个实现类org.apache.catalina.connector.CoyoteAdapter
,其主要职责如下:
-
将
org.apache.coyote.Request
和org.apache.coyote.Response
转为实现了标准Servlet
的org.apache.catalina.connector.Request
和org.apache.catalina.connector.Response
。 -
将请求体的
serverName
、URI
、version
传给Mapper
组件做映射,匹配到合适的Host
、Context
、Wrapper
。 -
将
Request
和Response
传给Container
处理,Engine
通过管道Pipeline
传给Host
,Host
再传给Context
,Context
再传给Wrapper
,Wrapper
是最终的Servlet
。
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
最后
作为过来人,小编是整理了很多进阶架构视频资料、面试文档以及PDF的学习资料,针对上面一套系统大纲小编也有对应的相关进阶架构视频资料
链图片转存中…(img-ZgIkENqr-1711008761495)]
最后
作为过来人,小编是整理了很多进阶架构视频资料、面试文档以及PDF的学习资料,针对上面一套系统大纲小编也有对应的相关进阶架构视频资料
[外链图片转存中…(img-IVsSc5CB-1711008761495)]
[外链图片转存中…(img-gniHBnZV-1711008761496)]