Tomcat Connector连接器原理
第1章:Tomcat Connector 概述
本章目标:理解 Connector 是什么、解决了什么问题、与 Container 如何协作。读完你应能口述端口监听—协议解析—请求适配—容器分发这一整条路径,并能看懂
<Connector>
的最小可用配置。
1.1 什么是 Tomcat Connector?
一句话:Connector 是 Tomcat 的“网络前台与协议栈”,负责把字节级的网络流(TCP/SSL/AJP)转换成 Tomcat 内部请求对象,再交给后端的 Container(Engine/Host/Context/Wrapper) 处理。
再打个比方(经典餐厅类比):
Connector = 前台接待 + 点单员
负责开门接客(监听端口、接受连接)
听懂客人语言(HTTP/1.1、HTTPS、AJP 协议解析)
把点单转成后厨能理解的格式(
org.apache.coyote.Request/Response
)并交给适配器(CoyoteAdapter
)
Container = 后厨(Engine/Host/Context/Wrapper)
拿到“点单”后,按Pipeline/Valve 与 Servlet 的业务逻辑做出“菜”并返回
主要包与角色:
org.apache.catalina.connector.Connector
:对外的<Connector>
组件,管理生命周期与配置。org.apache.coyote.ProtocolHandler
:协议处理门面,根据协议选择具体实现(如Http11NioProtocol
)。org.apache.tomcat.util.net.AbstractEndpoint
及其子类(NioEndpoint
/AprEndpoint
等):网络 I/O 端点与线程模型的核心。org.apache.coyote.http11.Http11Processor
:HTTP/1.1 协议请求解析器,完成请求行/头/体解析与状态机推进。org.apache.catalina.connector.CoyoteAdapter
:将 Coyote 层的 Request/Response 适配为 Servlet 容器可识别的对象,触发容器处理。
最小示意路径(纯文字“流程图”)
Socket -> Endpoint(Acceptor 接收连接) -> Poller/Selector(事件分发)-> Processor(Http11Processor 解析协议)-> CoyoteAdapter(适配)-> Engine/Host/Context/Wrapper(Pipeline/Valve)-> Servlet.service()-> 生成响应 -> Processor 序列化 -> Socket 写回
1.2 连接器的核心职责与设计目标
核心职责:
端口监听与连接接入:通过
Endpoint
绑定地址与端口,Acceptor
接收客户端连接。协议理解与状态机推进:
Processor
基于ProtocolHandler
的策略实现,解析请求行/头/体,驱动 HTTP/1.1 keep-alive、管线化(pipelining)、压缩、分块编码等。线程与资源调度:
Executor
线程池、LimitLatch
限流、Poller
事件循环,保证在高并发下的吞吐与响应延迟平衡。适配与分发:
CoyoteAdapter
将协议层对象转为HttpServletRequest/Response
,交由容器的 Pipeline/Valve 与 Mapper 完成精确路由。安全与传输:支持 HTTPS(SSL/TLS)、证书配置、ALPN(HTTP/2 相关)、以及 AJP(反向代理对接)。
设计目标:
解耦:网络/协议(Coyote)与业务容器(Catalina)隔离,便于替换 I/O 模型与协议实现。
高性能:提供 BIO/NIO/NIO2/APR 多种 I/O 模式;以
NioEndpoint
为主的多路复用方案降低线程成本。可扩展:可选共享
Executor
、自定义协议参数(maxThreads
、acceptCount
等),面向不同硬件与流量场景调优。健壮与可运维:完善的生命周期(
init/start/stop/destroy
),详细日志、JMX 暴露、连接超时/限流策略。
1.3 连接器与容器(Container)的协作关系
模块边界与调用方向:
Connector(Coyote 层)对上只暴露适配器接口:
Adapter service(Request, Response)
Container(Catalina 层)并不关心字节与协议细节,它接收一个“解析好的 HTTP 请求”,然后按 Mapper 找到对应的
Wrapper
(也就是某个Servlet
),沿 Pipeline/Valve 链调用。
关键桥梁:CoyoteAdapter
输入:
org.apache.coyote.Request
/org.apache.coyote.Response
输出:
org.apache.catalina.connector.Request
/org.apache.catalina.connector.Response
(封装为HttpServletRequest
/HttpServletResponse
视图)责任:映射 URI → Host/Context/Wrapper,触发 Filter 链与
Servlet.service()
;异常与错误页处理;请求结束时做资源回收与复用。
代码例 1:server.xml
中最小可用的 HTTP/1.1 NIO 连接器
场景:单端口 HTTP,使用默认
Http11NioProtocol
与NioEndpoint
<!-- conf/server.xml -->
<Service name="Catalina"><Connectorport="8080"protocol="org.apache.coyote.http11.Http11NioProtocol"connectionTimeout="20000"redirectPort="8443" /><Engine name="Catalina" defaultHost="localhost"><Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"/></Engine>
</Service>
说明:
protocol
明确绑定到Http11NioProtocol
(HTTP/1.1 + NIO 模型)。connectionTimeout
、redirectPort
为常见基础参数;HTTPS 通常在 8443。若省略
protocol
,Tomcat 会按默认协议选择(不同版本默认值可能不同,实践中建议显式声明以避免误判)。
代码例 2:从 Connector
到 ProtocolHandler
的构造(伪精简版)
目的是让你对“谁持有谁、谁调用谁”的依赖结构有直感。以下为讲解用的极简化片段(近似于 Tomcat 实现思路,便于理解):
// org.apache.catalina.connector.Connector(简化示意)
public class Connector extends LifecycleBase {private ProtocolHandler protocolHandler;private final Service service; // 所属 Service,后续可拿到 Engine/Mapper 等public Connector(String protocol) {// 根据字符串选择具体的 ProtocolHandler 实现this.protocolHandler = ProtocolHandlerFactory.create(protocol);this.protocolHandler.setAdapter(new CoyoteAdapter(service.getContainer()));}@Overrideprotected void initInternal() throws LifecycleException {// 1) 将自身配置(地址/端口/超时/线程池)下沉给 ProtocolHandler/Endpoint// 2) 调用 protocolHandler.init() 完成端口与资源的准备protocolHandler.init();}@Overrideprotected void startInternal() throws LifecycleException {// 启动网络端点与工作线程(Acceptor/Poller/Executor)protocolHandler.start();setState(LifecycleState.STARTED);}@Overrideprotected void stopInternal() throws LifecycleException {protocolHandler.stop();setState(LifecycleState.STOPPED);}@Overrideprotected void destroyInternal() throws LifecycleException {protocolHandler.destroy();}
}
// org.apache.coyote.ProtocolHandler(门面接口 - 简化)
public interface ProtocolHandler {void setAdapter(Adapter adapter); // CoyoteAdaptervoid init() throws Exception; // 资源准备、端口占用前的初始化void start() throws Exception; // 绑定端口、启动线程void pause(); // 暂停接受新连接void resume(); // 恢复void stop() throws Exception; // 停止线程与监听void destroy() throws Exception; // 释放底层资源
}
// org.apache.coyote.Adapter(适配器接口 - 简化)
public interface Adapter {void service(Request req, Response res) throws Exception;
}
要点:
Connector
不直接做网络 I/O,它把工作交给ProtocolHandler
;ProtocolHandler
再把 I/O 细节委托给Endpoint
(如NioEndpoint
)。Adapter
是把 Coyote Request/Response 交给 Catalina 容器 的唯一通道。
代码例 3:NIO 端点的基本线程角色(示意)
真实源码在
org.apache.tomcat.util.net
,下面仅为示意性的骨架,帮助记忆线程职责。
// 端点与线程角色(示意)
class NioEndpoint /* extends AbstractEndpoint */ {private Acceptor[] acceptors; // 接受连接private Poller[] pollers; // 事件轮询(基于 Selector)private Executor executor; // 处理 I/O 读写与业务解析(Processor)// Acceptor: 监听 ServerSocketChannel.accept()class Acceptor implements Runnable {public void run() {while (running) {SocketChannel ch = serverSock.accept(); // 接收新连接(非阻塞)ch.configureBlocking(false);// 注册到 Poller:后续在 Selector 上关注 OP_READ/OP_WRITEpollers[next()].register(ch);}}}// Poller: 主循环 select(),把就绪的连接分发到工作线程上class Poller implements Runnable {Selector selector;public void run() {while (running) {int n = selector.select(timeout);if (n > 0) {for (SelectionKey key : selector.selectedKeys()) {// 交给工作单元(SocketProcessor)在线程池中处理executor.execute(new SocketProcessor(key));}selector.selectedKeys().clear();}}}}// SocketProcessor:与 Http11Processor 协作,完成协议解析与读写class SocketProcessor implements Runnable {private final SelectionKey key;public void run() {// 从 Key 拿到附着的连接上下文,读取字节、调用 Processor.parse()// Processor 内部驱动请求状态机(请求行/头/体 -> CoyoteAdapter.service())}}
}
三句话记忆:
Acceptor 接、Poller 挑、Executor 干。
Processor
是“懂协议”的大脑;Endpoint
是“会 I/O 与调度”的身体。Adapter
是“翻译官”,把 Coyote 的话翻成 Catalina 能懂的语言。
第2章:Connector 的核心组件与属性
本章目标:理解 Connector 的构造与配置参数、ProtocolHandler 类型及线程/资源管理机制,为后续协议初始化与请求处理打基础。
2.1 Connector 的构造与配置参数
2.1.1 Connector 构造器解析
Tomcat 的 Connector
核心构造器分两类:
默认构造器
public Connector() {this(DEFAULT_PROTOCOL); }
默认使用
org.apache.coyote.http11.Http11NioProtocol
(Tomcat 9/10)适合常规 HTTP 服务
指定协议构造器
public Connector(String protocol) {this.protocolHandler = ProtocolHandlerFactory.create(protocol);this.protocolHandler.setAdapter(new CoyoteAdapter(service.getContainer())); }
分析:
protocolHandler
是协议栈入口,不同协议实例化不同实现:Http11NioProtocol
→ HTTP/1.1 + NIOHttp11AprProtocol
→ HTTP/1.1 + APR/nativeAjpNioProtocol
→ AJP + NIO
通过
CoyoteAdapter
将请求转给 Catalina 容器
2.1.2 核心配置参数
参数 | 默认值 | 说明 |
---|---|---|
port | 8080 | 监听端口 |
protocol | HTTP/1.1 | 绑定的协议实现 |
connectionTimeout | 20000ms | 连接超时时间 |
maxThreads | 200 | 处理请求的最大线程数 |
minSpareThreads | 10 | 空闲线程最小值 |
acceptCount | 100 | 未处理连接队列长度 |
redirectPort | 8443 | HTTPS 重定向端口 |
SSLEnabled | false | 是否启用 SSL/TLS |
小贴士:生产环境推荐明确声明
protocol
,避免默认值因版本不同产生差异。
2.1.3 示例:HTTP/HTTPS 两端口配置
<Service name="Catalina"><!-- HTTP --><Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"maxThreads="500" connectionTimeout="30000" redirectPort="8443"/><!-- HTTPS --><Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"maxThreads="500" SSLEnabled="true" scheme="https" secure="true"keystoreFile="conf/keystore.jks" keystorePass="changeit"clientAuth="false" sslProtocol="TLS"/>
</Service>
2.2 ProtocolHandler 的作用与类型
ProtocolHandler
是 Connector 的核心协议处理组件,负责端口监听、I/O 调度和请求解析。
2.2.1 核心职责
初始化端口和资源(
init()
)启动网络线程(
start()
)暂停/恢复请求接收(
pause()
/resume()
)停止线程和释放资源(
stop()
/destroy()
)
2.2.2 常用实现
类名 | 协议 | I/O 模型 |
---|---|---|
Http11NioProtocol | HTTP/1.1 | NIO Selector |
Http11Nio2Protocol | HTTP/1.1 | NIO2 异步 I/O |
Http11AprProtocol | HTTP/1.1 | APR/native |
AjpNioProtocol | AJP 1.3 | NIO Selector |
AjpAprProtocol | AJP 1.3 | APR/native |
关键类关系图(文字版):
Connector└─ ProtocolHandler (Http11NioProtocol)└─ AbstractProtocol└─ AbstractEndpoint (NioEndpoint / AprEndpoint)├─ Acceptor (接收连接)├─ Poller (事件轮询)└─ Executor (工作线程池)
2.2.3 示例:ProtocolHandler 初始化流程
ProtocolHandler handler = new Http11NioProtocol();
handler.setAdapter(new CoyoteAdapter(service.getContainer()));
handler.init(); // 初始化端口、线程池、Selector
handler.start(); // 启动 Acceptor & Poller 线程
注:
ProtocolHandler
对应Endpoint
,真正做 I/O 调度的是NioEndpoint
或AprEndpoint
。
2.3 线程池与资源限制(Executor / LimitLatch)
2.3.1 Executor 线程池
Connector 默认可创建内部线程池,也可指定共享 Executor
控制请求处理的并发数量
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"maxThreads="500" minSpareThreads="20"/> <Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"executor="tomcatThreadPool"/>
2.3.2 LimitLatch(连接限制器)
内置在
AbstractEndpoint
中,用于控制 活动连接数 和 排队队列长度作用:
防止短时间内过多连接压垮线程池
对未处理请求排队控制
acceptCount
文字示意逻辑:
新连接到来 ->if (activeConnections < maxThreads) -> 立即处理else if (waitingQueue < acceptCount) -> 放入队列else -> 拒绝连接/返回 503
2.3.3 配置建议
高并发生产环境:
maxThreads
:500~1000(根据 CPU & 内存调整)minSpareThreads
:保持 5~10% 的线程空闲acceptCount
:连接积压阈值,推荐 100~500
使用共享 Executor 有助于多个 Connector 共享线程池,减少线程创建开销
本章小结
Connector 构造器:决定使用哪种协议处理器及生命周期管理策略
ProtocolHandler:隔离协议逻辑与 I/O 模型,是 NIO/BIO/APR 的统一入口
线程与资源控制:
Executor
管理业务线程LimitLatch
限制并发连接,保证系统稳定
配置实践:
明确
protocol
、线程池、acceptCount对 HTTPS 与 AJP 提前规划端口与证书
第3章:ProtocolHandler 的初始化与协议绑定
本章目标:理解 Connector 如何通过 ProtocolHandler 将不同协议(HTTP/HTTPS/AJP)绑定到端口,并初始化线程与 I/O 模型,为请求处理做好准备。
3.1 HTTP/HTTPS/AJP 协议的差异与适配
3.1.1 HTTP/HTTPS
特性 | HTTP | HTTPS |
---|---|---|
协议 | HTTP/1.1 | HTTP/1.1 + SSL/TLS |
默认端口 | 80 / 8080 | 443 / 8443 |
安全性 | 明文 | 加密传输,支持证书认证 |
Tomcat实现 | Http11NioProtocol | Http11NioProtocol + SSLEngine |
HTTPS 实现机制:
Http11NioProtocol
创建NioEndpoint
通过
SSLHostConfig
绑定证书、密钥与协议版本在
Poller
/Selector
事件处理阶段,对读写的 ByteBuffer 做SSLEngine.wrap/unwrap
Coyote 层继续解析 HTTP 请求,Container 层完全透明
3.1.2 AJP 协议
用于前端代理(如 Apache HTTPD、Nginx + mod_jk)到 Tomcat 的二进制协议
低开销、适合内部负载均衡
Tomcat 实现类:
AjpNioProtocol
(NIO)AjpAprProtocol
(APR/native)
数据流:
AJP Message -> Coyote Request -> CoyoteAdapter -> Container
特点:
支持多路复用连接(Keep-Alive)
不直接支持 HTTPS(由前端代理终止 TLS)
3.2 Http11NioProtocol
的初始化流程
3.2.1 初始化调用链(文字流程图)
Connector.initInternal()-> ProtocolHandler.init()-> AbstractProtocol.init()-> AbstractEndpoint.init()-> Acceptor 初始化-> Poller 初始化-> Socket / Selector 准备-> SSL 配置解析(若启用)
3.2.2 关键源码片段解析
// Http11NioProtocol.init() (简化示意)
@Override
public void init() throws Exception {// 初始化底层网络端点getEndpoint().init();// SSL/TLS 配置if (SSLEnabled) {getEndpoint().setUseSSL(true);getEndpoint().setSSLHostConfigs(sslHostConfigs);}// 可扩展 Hook:ProtocolHandler 自定义参数初始化
}
// NioEndpoint.init() (核心)
public void init() throws IOException {if (!initialized) {// 创建 ServerSocketChannelserverSock = ServerSocketChannel.open();serverSock.configureBlocking(false);serverSock.socket().bind(new InetSocketAddress(port), acceptCount);// 初始化 Poller 线程池pollers = new Poller[pollerCount];for (int i = 0; i < pollers.length; i++) {pollers[i] = new Poller();}// 初始化 LimitLatch / ExecutorlimitLatch = new LimitLatch(maxConnections);executor = createExecutor();initialized = true;}
}
3.2.3 端口绑定与线程启动
@Override
public void start() throws Exception {// 启动 Poller / Acceptor 线程for (Poller poller : pollers) {executor.execute(poller);}for (Acceptor acceptor : acceptors) {executor.execute(acceptor);}// 设置 Connector 状态started = true;
}
注释:
Acceptor
:监听端口并接收连接
Poller
:事件轮询,选择就绪 Socket
Executor
:处理 SocketProcessor / Http11Processor
3.3 端口监听与 SSL/TLS 配置解析
3.3.1 SSLHostConfig 与 SSL 配置
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"SSLEnabled="true"keystoreFile="conf/keystore.jks"keystorePass="changeit"sslProtocol="TLS" />
解析流程:
Http11NioProtocol
读取keystoreFile/keystorePass
生成
SSLHostConfig
对象NioEndpoint
在接收数据前,将 SocketChannel 包装为SSLEngine
读写事件触发时:
read()
->SSLEngine.unwrap()
-> ByteBufferwrite()
->SSLEngine.wrap()
-> SocketChannel
3.3.2 端口监听逻辑
ServerSocketChannel.open()
→ 配置非阻塞 →bind()
Acceptor
循环调用accept()
新连接注册到 Poller → 交由 Selector 监听读/写事件
避免阻塞主线程,通过线程池并发处理请求
3.3.3 HTTPS 与 HTTP 的复用
HTTPS 和 HTTP 可以共用
Http11NioProtocol
,只在SSLEnabled=true
时增加SSLEngine
层Connector 可以同时配置多个端口,分别监听 HTTP/HTTPS,甚至共享同一个 Executor
第4章:连接器的生命周期管理
本章目标:掌握 Connector 生命周期各阶段的职责与执行顺序,理解资源准备、线程启动、优雅关闭和销毁的底层机制。
4.1 initInternal
:资源准备与依赖校验
4.1.1 方法调用链
Connector.initInternal()-> ProtocolHandler.init()-> AbstractProtocol.init()-> AbstractEndpoint.init()-> Acceptor / Poller 初始化-> SocketChannel / Selector 准备-> SSL 配置解析(若启用)
4.1.2 核心职责
配置校验
检查端口合法性、线程池参数、协议类型
初始化共享 Executor(如果未指定则创建默认线程池)
初始化网络端点
创建
ServerSocketChannel
或AprEndpoint
配置非阻塞模式、绑定端口
初始化事件轮询组件(Poller / Selector)
SSL/TLS 初始化(如果
SSLEnabled=true
)读取证书和密钥
创建
SSLHostConfig
准备
SSLEngine
对象
4.1.3 核心源码示例(简化版)
@Override
protected void initInternal() throws LifecycleException {// 1. 校验协议与端口checkPortValidity();// 2. 初始化 ProtocolHandlertry {protocolHandler.init();} catch (Exception e) {throw new LifecycleException("ProtocolHandler init failed", e);}// 3. 初始化资源标记initialized = true;
}
注释:
initInternal
只做资源准备,不会启动监听线程所有 I/O 对象、线程池、SSL 引擎等在此阶段创建完成
4.2 startInternal
:端口绑定与线程启动
4.2.1 方法调用链
Connector.startInternal()-> ProtocolHandler.start()-> AbstractProtocol.start()-> AbstractEndpoint.start()-> 启动 Acceptor 线程-> 启动 Poller 线程-> 准备工作线程(Executor)
4.2.2 核心职责
端口绑定与监听
调用
ServerSocketChannel.bind()
启动
Acceptor
循环接收连接
事件轮询启动
Poller 循环 select()
将就绪连接交给 SocketProcessor
线程池激活
Executor 开始接收任务
SocketProcessor 或 Http11Processor 由线程池调度
4.2.3 核心源码示例(简化版)
@Override
protected void startInternal() throws LifecycleException {try {protocolHandler.start(); // 启动线程池、Acceptor、PollersetState(LifecycleState.STARTED);} catch (Exception e) {throw new LifecycleException("ProtocolHandler start failed", e);}
}
注释:
连接器真正开始提供服务的是
startInternal
阶段此阶段后,端口可以接受客户端请求,线程池可处理请求
4.3 stopInternal
与 destroyInternal
:资源释放与优雅关闭
4.3.1 stopInternal
:优雅关闭
调用链:
Connector.stopInternal()-> ProtocolHandler.stop()-> AbstractProtocol.stop()-> AbstractEndpoint.stop()-> 停止 Acceptor / Poller-> 停止线程池-> 不再接受新连接
核心逻辑:
立即停止接收新连接(Acceptor)
Poller 停止事件轮询
已接收连接继续处理完成
线程池不再接收新任务,等待现有任务执行完毕
4.3.2 destroyInternal
:彻底释放资源
调用链:
Connector.destroyInternal()-> ProtocolHandler.destroy()-> AbstractProtocol.destroy()-> AbstractEndpoint.destroy()-> 关闭 ServerSocket-> 释放 Selector-> 清理内部缓冲区和连接对象
核心职责:
清理底层 I/O 对象
回收线程池(如果是 Connector 自建)
释放内存缓存、SSL 引擎、队列等资源
Connector 不可再次使用,生命周期结束
4.3.3 源码示例(简化版)
@Override
protected void stopInternal() throws LifecycleException {try {protocolHandler.stop(); // 停止线程与事件轮询setState(LifecycleState.STOPPED);} catch (Exception e) {throw new LifecycleException("ProtocolHandler stop failed", e);}
}@Override
protected void destroyInternal() throws LifecycleException {try {protocolHandler.destroy(); // 彻底释放资源setState(LifecycleState.DESTROYED);} catch (Exception e) {throw new LifecycleException("ProtocolHandler destroy failed", e);}
}
4.4 生命周期执行顺序总结
生命周期方法 | 核心职责 | 备注 |
---|---|---|
initInternal | 资源准备、参数校验、SSL/Endpoint 初始化 | 不启动线程 |
startInternal | 启动 Acceptor/Poller/Executor、端口绑定 | 端口可接受请求 |
stopInternal | 停止接收新连接、线程池优雅关闭 | 已处理连接继续完成 |
destroyInternal | 彻底释放资源、关闭端口/Selector | Connector 不可再用 |
文字类比:
initInternal
= 准备厨房与原料startInternal
= 开门营业,服务客户stopInternal
= 停止接待新客户,完成现有订单destroyInternal
= 关店打烊,清理厨房和餐具
第5章:网络通信模型详解
本章目标:理解 Tomcat 支持的多种 I/O 模型及其应用场景,掌握 NioEndpoint 的核心线程架构(Acceptor、Poller、Executor)及事件处理机制。
5.1 BIO / NIO / NIO2 / APR 的区别与适用场景
模型 | 简介 | 优点 | 缺点 | 适用场景 |
---|---|---|---|---|
BIO (Blocking I/O) | 每个连接一个线程阻塞 | 实现简单,调试方便 | 线程消耗大,高并发易 OOM | 并发量小,低流量 |
NIO (Non-blocking I/O) | 通过 Selector 多路复用 | 高并发,线程少 | 编程复杂,需事件轮询 | 高并发 HTTP/HTTPS |
NIO2 (Asynchronous I/O) | 异步回调方式处理事件 | 高性能,事件驱动 | 依赖 JDK 异步 API,兼容性 | 大规模异步处理 |
APR (Apache Portable Runtime) | 调用本地 OS 原生 I/O | 高性能,零拷贝 | 需 native 库支持,部署复杂 | 高吞吐量,低延迟环境 |
总结:
BIO → 简单但不适合大并发
NIO → 高并发通用方案,Tomcat 默认
NIO2 → JDK 异步 I/O,适合异步应用
APR → 极致性能场景,但部署复杂
5.2 NioEndpoint
的实现机制(Acceptor / Poller / Selector)
5.2.1 核心组成
NioEndpoint├─ ServerSocketChannel // 监听端口├─ Acceptor 线程 // 接收新连接├─ Poller 线程数组 // Selector 事件轮询├─ SocketProcessor // 处理就绪连接的请求└─ Executor / ThreadPool // 处理业务请求
5.2.2 Acceptor 线程逻辑
循环监听
ServerSocketChannel
当有新连接:
检查 LimitLatch(最大并发控制)
设置非阻塞模式
分配到 Poller 线程
class Acceptor implements Runnable {@Overridepublic void run() {while (running) {SocketChannel socket = serverSock.accept();if (socket != null) {configureSocket(socket);poller.nextProcessor(socket); // 分配 Poller}}} }
注:Acceptor 线程尽量少数(通常1~2个),避免接收成为瓶颈。
5.2.3 Poller 线程逻辑
每个 Poller 管理一组连接
使用
Selector
监听读/写事件将就绪连接提交给线程池处理
class Poller implements Runnable {@Overridepublic void run() {while (running) {selector.select(timeout);for (SelectionKey key : selector.selectedKeys()) {if (key.isReadable()) {executor.execute(new SocketProcessor(key));}}}} }
注释:
Selector
实现多路复用,减少线程数每个 Poller 可以管理上千个连接
5.2.4 SocketProcessor
将网络数据读取成
ByteBuffer
解析 HTTP 请求头与请求体
调用
Http11Processor
处理请求完成响应后写回客户端
class SocketProcessor implements Runnable {@Overridepublic void run() {Http11Processor processor = new Http11Processor(socket);processor.process();} }
5.3 高性能通信的优化策略
5.3.1 缓冲区复用
避免每次请求分配新的 ByteBuffer
使用缓冲池(BufferPool)
减少 GC 压力
ByteBuffer buffer = bufferPool.allocate(); try {socket.read(buffer); } finally {bufferPool.recycle(buffer); }
5.3.2 Poller 调优
Poller 线程数量 = CPU 核心数 × 1~2
减少 context switch,提高事件处理效率
5.3.3 Executor 调优
maxThreads:控制业务线程上限
minSpareThreads:保证空闲线程应对突发流量
对多个 Connector 可共享 Executor,减少线程开销
5.3.4 事件轮询策略
selector.select(timeout)
调整超时避免空轮询(CPU 消耗高)
对高并发应用可启用
epoll
/kqueue
(APR 或 NIO2)
第6章:请求处理流程深度解析
本章目标:理解 Tomcat Connector 如何将客户端请求从底层 Socket 转换为 Servlet 容器可处理的
HttpServletRequest
,并掌握关键处理类和调用链路。
6.1 Socket 到 HttpServletRequest 的转换过程
6.1.1 请求接入链路概览
客户端 Socket 请求|v
ServerSocketChannel.accept() (Acceptor)|v
Poller.select() -> SocketProcessor|v
Http11Processor 解析 HTTP 消息|v
CoyoteRequest / CoyoteResponse|v
CoyoteAdapter|v
Catalina Container (Engine -> Host -> Context -> Wrapper)|v
ServletService / Filter / Valve 处理
注释:这个链路体现了 Tomcat 的 Connector → Coyote → Adapter → Container 分层设计。
6.1.2 数据读取与封装
SocketProcessor
读取网络数据到ByteBuffer
解析请求行(Method, URI, Protocol)
解析请求头(Headers)和请求体(Body)
封装为
CoyoteRequest
对象ByteBuffer buffer = bufferPool.allocate(); int bytesRead = socket.read(buffer); if (bytesRead > 0) {Http11InputBuffer inputBuffer = new Http11InputBuffer(buffer);inputBuffer.parseRequestLine();inputBuffer.parseHeaders();CoyoteRequest request = new CoyoteRequest();request.setMethod(inputBuffer.getMethod());request.setRequestURI(inputBuffer.getRequestURI());request.setProtocol(inputBuffer.getProtocol());request.setHeaders(inputBuffer.getHeaders()); }
注释:
Http11InputBuffer
负责将 ByteBuffer 转为结构化 HTTP 请求支持分块传输、Content-Length、Transfer-Encoding 等复杂场景
6.2 Http11Processor 的请求解析逻辑
6.2.1 核心职责
解析请求行与请求头
解析请求体(支持表单、文件上传、JSON 等)
处理 Keep-Alive 与管线请求
构造 CoyoteRequest / CoyoteResponse
交给 CoyoteAdapter 分发给容器
6.2.2 核心源码流程(简化版)
public void process() {inputBuffer.parseRequestLine();inputBuffer.parseHeaders();request.setMethod(inputBuffer.getMethod());request.setRequestURI(inputBuffer.getRequestURI());request.setProtocol(inputBuffer.getProtocol());request.setHeaders(inputBuffer.getHeaders());if (request.isExpectContinue()) {response.sendContinue();}adapter.service(request, response); // 调用容器处理
}
注释:
Http11Processor
直接处理 HTTP/1.1 协议细节可处理长连接、分块请求、管线请求
Expect: 100-continue
支持避免大请求体浪费带宽
6.3 CoyoteAdapter 与 Servlet 容器的交互
6.3.1 CoyoteAdapter 作用
作为 Coyote 层和 Catalina 容器的桥梁
将
CoyoteRequest
转换为HttpServletRequest
调用
StandardWrapper
/ApplicationFilterChain
执行 Servlet返回响应后将数据写回
CoyoteResponse
6.3.2 核心源码示意
public void service(Request coyoteRequest, Response coyoteResponse) {HttpServletRequest request = coyoteRequest.getRequest();HttpServletResponse response = coyoteResponse.getResponse();try {// 调用容器处理请求wrapper.getPipeline().getFirst().invoke(request, response);} catch (ServletException | IOException e) {response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);}
}
注释:
Pipeline
+Valve
架构:支持 Filter、Interceptor、Valve 等扩展
StandardWrapper
包含 Servlet 实例及其生命周期管理
6.3.3 响应回写流程
Servlet 执行完成 → 写入
CoyoteResponse
CoyoteResponse
调用底层SocketChannel.write()
Poller/SocketProcessor 处理写事件,完成客户端响应
ByteBuffer buffer = response.getByteBuffer();
while(buffer.hasRemaining()) {socket.write(buffer);
}
注释:
支持异步写和缓冲区复用
Keep-Alive 连接可复用 Socket,提高性能
本章小结
请求链路:Socket → SocketProcessor → Http11Processor → CoyoteAdapter → Container
Http11Processor:核心 HTTP 解析逻辑,支持分块传输、长连接
CoyoteAdapter:桥接 Connector 与容器,实现请求分发与响应回写
熟悉该流程,有助于:
调试请求解析异常
分析慢请求、长连接性能瓶颈
理解 Filter/Valve 执行顺序
第7章:性能优化与配置实践
本章目标:从性能角度分析 Connector 的瓶颈与优化策略,提供生产环境的调优模板和常见问题解决方案。
7.1 连接器参数调优(maxThreads
、acceptCount
等)
7.1.1 核心参数说明
参数 | 默认值 | 作用 | 调优建议 |
---|---|---|---|
maxThreads | 200 | 线程池最大线程数 | 根据 CPU 核心数和并发请求量调整,一般为 CPU × 2~4 |
minSpareThreads | 10 | 保持空闲线程数 | 避免突发请求等待,建议 10~20 |
acceptCount | 100 | 连接队列长度 | 高并发时增大以避免拒绝连接 |
connectionTimeout | 20000 ms | Socket 超时 | 根据业务特性设置,避免连接长时间占用 |
keepAliveTimeout | 60000 ms | 长连接空闲超时 | 避免空闲连接占用线程或缓冲区 |
7.1.2 配置示例(HTTP)
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"maxThreads="500"minSpareThreads="20"acceptCount="200"connectionTimeout="20000"keepAliveTimeout="60000" />
7.1.3 配置示例(HTTPS)
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"SSLEnabled="true"keystoreFile="conf/keystore.jks"keystorePass="changeit"sslProtocol="TLS"maxThreads="400"acceptCount="150"connectionTimeout="15000" />
注释:
maxThreads
和Executor
配合使用,可共享线程池
acceptCount
决定操作系统 backlog 队列长度,高并发建议增大
7.2 高并发场景下的配置建议
7.2.1 线程池优化
共享 Executor:多个 Connector 共享同一个线程池,减少线程开销
线程数调整:高并发场景按 CPU 核心 × 2~4 设置
空闲线程保留:避免突发流量等待线程启动
7.2.2 I/O 模型选择
NIO/NIO2:高并发 HTTP/HTTPS 推荐
APR:极致吞吐量,需 native 库支持
BIO:仅用于低并发测试或兼容场景
7.2.3 Keep-Alive 与长连接
合理设置
keepAliveTimeout
配合
maxKeepAliveRequests
控制单连接最大请求数避免线程长时间占用,提高吞吐量
7.2.4 缓冲区与 Poller 调优
调整
socketBuffer
大小,提升大请求吞吐量Poller 线程数量 = CPU 核心数 × 1~2
避免空轮询和 CPU 占用过高
7.3 常见问题排查与解决方案
问题 | 可能原因 | 解决方案 |
---|---|---|
连接被拒绝 | acceptCount 队列满,操作系统 backlog 不够 | 增大 acceptCount,调整操作系统 TCP backlog |
响应慢 | maxThreads 不够或线程池阻塞 | 增大 maxThreads,优化 Executor 使用,检查阻塞 Servlet/Filter |
高 CPU | Poller 空轮询、线程竞争 | 调整 Poller 数量,优化 Selector 超时,避免无效循环 |
内存泄漏 | 长连接未关闭、BufferPool 资源未回收 | 检查 keepAliveTimeout,BufferPool 使用,释放未关闭连接 |
SSL 握手慢 | 证书解析或 Cipher 配置不合理 | 优化 keystore,启用支持的 CipherSuite,减少 SSL 初始化开销 |
7.3.1 日志与监控建议
启用 Tomcat AccessLog,统计请求量和响应时间
使用 JMX 监控 Connector 线程池状态
监控 Selector、Poller、Acceptor 队列长度,及时发现瓶颈