当前位置: 首页 > news >正文

第三章-Tomcat请求处理原理 - 指南

第三章-Tomcat请求处理原理 - 指南

⚙️ 第三章:Tomcat 请求处理原理

目录


3.1 请求到达与解析

3.1.1 请求到达流程

整体流程图
客户端HTTP请求
网络层接收
Connector监听端口
协议解析
CoyoteAdapter适配
Request对象创建
Engine路由
Host匹配
Context匹配
Wrapper匹配
Servlet调用
详细步骤说明
1. 网络层接收
// NIO 连接器接收请求
public class Http11NioProtocol extends AbstractHttp11Protocol<NioChannel> {@Overrideprotected AbstractEndpoint.Handler<NioChannel> getHandler() {return new Http11ConnectionHandler(this);}}
2. 协议解析
// HTTP 协议解析器
public class Http11Processor extends AbstractProcessorLight {
@Override
public SocketState service(SocketWrapperBase<?> socketWrapper)throws IOException {// 1. 解析请求行if (!inputBuffer.parseRequestLine(keptAlive)) {if (inputBuffer.getParsingRequestLinePhase() == -1) {return SocketState.UPGRADING;} else if (handleIncompleteRequestLineRead()) {break;}}// 2. 解析请求头if (!inputBuffer.parseHeaders()) {if (inputBuffer.getParsingRequestLinePhase() == -1) {return SocketState.UPGRADING;} else if (handleIncompleteRequestLineRead()) {break;}}// 3. 处理请求return process(socketWrapper);}}
3. CoyoteAdapter 适配
// CoyoteAdapter 适配器
public class CoyoteAdapter implements Adapter {
@Override
public void service(org.apache.coyote.Request req,
org.apache.coyote.Response res)
throws Exception {
// 1. 创建 Request 和 Response 对象
Request request = (Request) req.getNote(ADAPTER_NOTES);
Response response = (Response) res.getNote(ADAPTER_NOTES);
if (request == null) {
request = connector.createRequest();
request.setCoyoteRequest(req);
response = connector.createResponse();
response.setCoyoteResponse(res);
}
// 2. 设置请求属性
request.setCoyoteRequest(req);
response.setCoyoteResponse(res);
// 3. 调用容器的 Pipeline
connector.getService().getContainer().getPipeline()
.getFirst().invoke(request, response);
}
}

3.1.2 请求解析详解

HTTP 请求解析
// 请求行解析
public class Http11InputBuffer {
public boolean parseRequestLine(boolean keptAlive) throws IOException {
// 解析方法
if (parsingRequestLinePhase == 0) {
if (parsingRequestLineStart == -1) {
parsingRequestLineStart = 0;
}
byte chr = 0;
do {
int pos = parsingRequestLineStart;
byte[] buf = bufferedReadBuffer;
int end = lastValid;
while (pos < end) {
chr = buf[pos];
if (chr == Constants.SP || chr == Constants.HTAB) {
break;
}
pos++;
}
if (pos == end) {
if (keptAlive) {
return false;
}
throw new IOException("Request line too long");
}
parsingRequestLineStart = pos;
parsingRequestLinePhase = 1;
} while (chr == Constants.SP || chr == Constants.HTAB);
}
// 解析 URI
if (parsingRequestLinePhase == 1) {
return parseRequestLineURI();
}
// 解析协议版本
if (parsingRequestLinePhase == 2) {
return parseRequestLineProtocol();
}
return true;
}
}
请求头解析
// 请求头解析
public boolean parseHeaders() throws IOException {
if (parsingHeader) {
return true;
}
parsingHeader = true;
while (true) {
// 读取一行
if (!fill()) {
return false;
}
// 检查是否为空行(请求头结束)
if (buf[pos] == Constants.CR || buf[pos] == Constants.LF) {
parsingHeader = false;
return true;
}
// 解析单个请求头
if (!parseHeader()) {
return false;
}
}
}

3.2 请求分发机制

3.2.1 路由层次结构

路由流程图
匹配
不匹配
匹配
不匹配
匹配
不匹配
HTTP请求
Connector
CoyoteAdapter
Engine
Host匹配
Host
默认Host
Context匹配
Context
默认Context
Wrapper匹配
Wrapper
默认Servlet
Servlet
详细路由步骤
1. Engine 路由到 Host
// StandardEngine 路由逻辑
public class StandardEngine extends ContainerBase implements Engine {
@Override
public void invoke(Request request, Response response)
throws IOException, ServletException {
// 1. 获取请求的 Host 头
String hostname = request.getServerName();
if (hostname == null) {
hostname = getDefaultHost();
}
// 2. 查找对应的 Host
Host host = findChild(hostname);
if (host == null) {
host = findChild(getDefaultHost());
}
// 3. 调用 Host 的 invoke 方法
if (host != null) {
host.invoke(request, response);
} else {
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
}
}
}
2. Host 路由到 Context
// StandardHost 路由逻辑
public class StandardHost extends ContainerBase implements Host {
@Override
public void invoke(Request request, Response response)
throws IOException, ServletException {
// 1. 获取请求路径
String requestPath = request.getRequestPath();
// 2. 查找匹配的 Context
Context context = findContext(requestPath);
if (context == null) {
context = findContext("");
}
// 3. 调用 Context 的 invoke 方法
if (context != null) {
context.invoke(request, response);
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
private Context findContext(String path) {
// 1. 精确匹配
Context context = contexts.get(path);
if (context != null) {
return context;
}
// 2. 最长前缀匹配
String longestMatch = "";
Context longestContext = null;
for (Map.Entry<String, Context> entry : contexts.entrySet()) {String contextPath = entry.getKey();if (path.startsWith(contextPath) &&contextPath.length() > longestMatch.length()) {longestMatch = contextPath;longestContext = entry.getValue();}}return longestContext;}}
3. Context 路由到 Wrapper
// StandardContext 路由逻辑
public class StandardContext extends ContainerBase implements Context {
@Override
public void invoke(Request request, Response response)
throws IOException, ServletException {
// 1. 获取 Servlet 路径
String servletPath = request.getServletPath();
// 2. 查找匹配的 Wrapper
Wrapper wrapper = findWrapper(servletPath);
if (wrapper == null) {
wrapper = findWrapper("");
}
// 3. 调用 Wrapper 的 invoke 方法
if (wrapper != null) {
wrapper.invoke(request, response);
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
}
private Wrapper findWrapper(String path) {
// 1. 精确匹配
Wrapper wrapper = wrappers.get(path);
if (wrapper != null) {
return wrapper;
}
// 2. 模式匹配
for (Map.Entry<String, Wrapper> entry : wrappers.entrySet()) {String pattern = entry.getKey();if (matchPattern(path, pattern)) {return entry.getValue();}}return null;}}
4. Wrapper 调用 Servlet
// StandardWrapper 调用逻辑
public class StandardWrapper extends ContainerBase implements Wrapper {
@Override
public void invoke(Request request, Response response)
throws IOException, ServletException {
// 1. 获取 Servlet 实例
Servlet servlet = allocate();
// 2. 调用 Servlet 的 service 方法
try {
servlet.service(request, response);
} finally {
// 3. 释放 Servlet 实例
deallocate(servlet);
}
}
private Servlet allocate() throws ServletException {
// 1. 检查是否已加载
if (instance == null) {
load();
}
// 2. 返回 Servlet 实例
return instance;
}
}

3.2.2 路由配置示例

Host 配置
<Host name="localhost" appBase="webapps"unpackWARs="true" autoDeploy="true">
<!-- 应用上下文 --><Context path="/myapp" docBase="myapp" /><Context path="/api" docBase="api" /><!-- 默认应用 --><Context path="" docBase="ROOT" /></Host>
Context 配置
<Context path="/myapp" docBase="myapp"><!-- Servlet 映射 --><Servlet name="MyServlet" class="com.example.MyServlet" /><ServletMapping name="MyServlet" urlPattern="/myservlet" /><!-- 过滤器 --><Filter name="MyFilter" class="com.example.MyFilter" /><FilterMapping name="MyFilter" urlPattern="/*" /></Context>

3.3 NIO 事件循环模型

3.3.1 NIO 模型概述

事件循环架构
Acceptor线程
接收连接
注册到Poller
Poller线程
事件循环
处理I/O事件
Worker线程池
处理业务逻辑
核心组件
1. Acceptor 线程
// Acceptor 线程
public class Acceptor<U> extends AbstractEndpoint.Acceptor<U> {@Overridepublic void run() {while (endpoint.isRunning()) {try {// 1. 接受连接SocketChannel socket = serverSock.accept();// 2. 设置非阻塞模式socket.configureBlocking(false);// 3. 注册到 PollergetPoller0().register(socket);} catch (Exception e) {// 处理异常}}}}
2. Poller 线程
// Poller 线程
public class Poller implements Runnable {
@Override
public void run() {
while (true) {
try {
// 1. 等待事件
int keyCount = selector.select(selectorTimeout);
// 2. 处理就绪的通道
if (keyCount > 0) {
Iterator<SelectionKey> iterator =selector.selectedKeys().iterator();while (iterator.hasNext()) {SelectionKey key = iterator.next();iterator.remove();// 3. 处理 I/O 事件processKey(key);}}} catch (Exception e) {// 处理异常}}}private void processKey(SelectionKey key) {if (key.isReadable()) {// 处理读事件processRead(key);} else if (key.isWritable()) {// 处理写事件processWrite(key);}}}
3. Worker 线程池
// Worker 线程池
public class Executor implements java.util.concurrent.Executor {
private final ThreadPoolExecutor executor;
@Override
public void execute(Runnable command) {
// 1. 检查线程池状态
if (executor.isShutdown()) {
return;
}
// 2. 提交任务到线程池
executor.execute(command);
}
private void processRequest(SocketChannel channel) {
// 1. 创建请求处理任务
Runnable task = new RequestProcessor(channel);
// 2. 提交到线程池
executor.execute(task);
}
}

3.3.2 事件处理流程

详细处理步骤
// 请求处理流程
public class Http11NioProcessor extends AbstractProcessorLight {
@Override
public SocketState service(SocketWrapperBase<NioChannel> socketWrapper)throws IOException {// 1. 读取请求数据if (!inputBuffer.parseRequestLine(keptAlive)) {return SocketState.UPGRADING;}// 2. 解析请求头if (!inputBuffer.parseHeaders()) {return SocketState.UPGRADING;}// 3. 处理请求return process(socketWrapper);}private SocketState process(SocketWrapperBase<NioChannel> socketWrapper)throws IOException {// 1. 创建请求和响应对象Request request = new Request();Response response = new Response();// 2. 设置请求属性request.setCoyoteRequest(coyoteRequest);response.setCoyoteResponse(coyoteResponse);// 3. 调用适配器adapter.service(request, response);// 4. 处理响应return processResponse(request, response);}}

3.4 请求处理详细流程

3.4.1 完整处理流程

流程图
Client Connector CoyoteAdapter Engine Host Context Wrapper Servlet HTTP请求 解析请求 调用适配器 路由到Engine 路由到Host 路由到Context 路由到Wrapper 调用Servlet 返回响应 返回响应 返回响应 返回响应 返回响应 返回响应 HTTP响应 Client Connector CoyoteAdapter Engine Host Context Wrapper Servlet
详细代码实现
1. 请求接收
// 连接器接收请求
public class Http11NioProtocol extends AbstractHttp11Protocol<NioChannel> {@Overrideprotected AbstractEndpoint.Handler<NioChannel> getHandler() {return new Http11ConnectionHandler(this);}}// 连接处理器public class Http11ConnectionHandler extends AbstractConnectionHandler<NioChannel,Http11NioProcessor> {@Overrideprotected Http11NioProcessor createProcessor() {Http11NioProcessor processor = new Http11NioProcessor(this);processor.setAdapter(getAdapter());return processor;}}
2. 请求解析
// 请求解析器
public class Http11InputBuffer {
public boolean parseRequestLine(boolean keptAlive) throws IOException {
// 解析请求行:方法 URI 协议版本
// GET /myapp/servlet HTTP/1.1
return parseRequestLineInternal(keptAlive);
}
public boolean parseHeaders() throws IOException {
// 解析请求头
// Host: localhost:8080
// Content-Type: application/json
// Content-Length: 100
return parseHeadersInternal();
}
}
3. 请求路由
// 请求路由
public class CoyoteAdapter implements Adapter {
@Override
public void service(org.apache.coyote.Request req,
org.apache.coyote.Response res)
throws Exception {
// 1. 创建 Request 和 Response 对象
Request request = (Request) req.getNote(ADAPTER_NOTES);
Response response = (Response) res.getNote(ADAPTER_NOTES);
if (request == null) {
request = connector.createRequest();
request.setCoyoteRequest(req);
response = connector.createResponse();
response.setCoyoteResponse(res);
}
// 2. 设置请求属性
request.setCoyoteRequest(req);
response.setCoyoteResponse(res);
// 3. 调用容器的 Pipeline
connector.getService().getContainer().getPipeline()
.getFirst().invoke(request, response);
}
}
4. Servlet 调用
// Servlet 调用
public class StandardWrapper extends ContainerBase implements Wrapper {
@Override
public void invoke(Request request, Response response)
throws IOException, ServletException {
// 1. 获取 Servlet 实例
Servlet servlet = allocate();
// 2. 调用 Servlet 的 service 方法
try {
servlet.service(request, response);
} finally {
// 3. 释放 Servlet 实例
deallocate(servlet);
}
}
}

3.5 响应生成与返回

3.5.1 响应生成流程

响应流程图
Servlet处理
设置响应头
写入响应体
刷新缓冲区
关闭连接
返回给客户端
详细实现
1. 响应头设置
// 响应头设置
public class Http11OutputBuffer extends AbstractOutputBuffer {
@Override
public void sendHeaders() throws IOException {
// 1. 设置状态行
sendStatusLine();
// 2. 设置响应头
for (String name : response.getHeaderNames()) {
String value = response.getHeader(name);
sendHeader(name, value);
}
// 3. 设置空行
sendCRLF();
}
private void sendStatusLine() throws IOException {
// HTTP/1.1 200 OK
String statusLine = "HTTP/1.1 " + response.getStatus() + " " +
response.getMessage() + "\r\n";
write(statusLine.getBytes());
}
}
2. 响应体写入
// 响应体写入
public class Http11OutputBuffer extends AbstractOutputBuffer {
@Override
public void write(byte[] b, int off, int len) throws IOException {
// 1. 检查缓冲区大小
if (len > buffer.length - count) {
flush();
}
// 2. 写入缓冲区
System.arraycopy(b, off, buffer, count, len);
count += len;
// 3. 检查是否需要刷新
if (count >= buffer.length) {
flush();
}
}
@Override
public void flush() throws IOException {
// 1. 写入数据到网络
socketWrapper.write(buffer, 0, count);
// 2. 清空缓冲区
count = 0;
}
}
3. 连接管理
// 连接管理
public class Http11NioProcessor extends AbstractProcessorLight {
@Override
public SocketState process(SocketWrapperBase<NioChannel> socketWrapper)throws IOException {// 1. 处理请求SocketState state = service(socketWrapper);// 2. 处理响应if (state == SocketState.OPEN) {state = processResponse(request, response);}// 3. 管理连接if (state == SocketState.OPEN) {if (keptAlive) {// 保持连接return SocketState.OPEN;} else {// 关闭连接return SocketState.CLOSED;}}return state;}}

3.6 性能优化要点

3.6.1 连接优化

连接池配置
<!-- 连接器优化配置 --><Connector port="8080" protocol="HTTP/1.1"connectionTimeout="20000"maxThreads="200"minSpareThreads="10"maxSpareThreads="50"acceptCount="100"maxConnections="8192"keepAliveTimeout="60000"maxKeepAliveRequests="100" />
线程池优化
// 线程池配置
public class StandardThreadExecutor implements Executor {
private final ThreadPoolExecutor executor;
public StandardThreadExecutor() {
// 核心线程数
int corePoolSize = 10;
// 最大线程数
int maximumPoolSize = 200;
// 空闲时间
long keepAliveTime = 60L;
// 时间单位
TimeUnit unit = TimeUnit.SECONDS;
// 工作队列
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(100);executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);}}

3.6.2 缓冲区优化

输入缓冲区
// 输入缓冲区配置
public class Http11InputBuffer {
private static final int DEFAULT_BUFFER_SIZE = 8192;
private static final int MAX_BUFFER_SIZE = 65536;
private byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
private int pos = 0;
private int lastValid = 0;
public void expand(int size) {
if (size > MAX_BUFFER_SIZE) {
throw new IllegalArgumentException("Buffer size too large");
}
byte[] newBuffer = new byte[size];
System.arraycopy(buffer, 0, newBuffer, 0, lastValid);
buffer = newBuffer;
}
}
输出缓冲区
// 输出缓冲区配置
public class Http11OutputBuffer {
private static final int DEFAULT_BUFFER_SIZE = 8192;
private static final int MAX_BUFFER_SIZE = 65536;
private byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
private int count = 0;
public void expand(int size) {
if (size > MAX_BUFFER_SIZE) {
throw new IllegalArgumentException("Buffer size too large");
}
byte[] newBuffer = new byte[size];
System.arraycopy(buffer, 0, newBuffer, 0, count);
buffer = newBuffer;
}
}

3.6.3 压缩优化

GZIP 压缩
<!-- 启用压缩 --><Connector port="8080" protocol="HTTP/1.1"compression="on"compressionMinSize="2048"compressableMimeType="text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json" />
压缩实现
// 压缩实现
public class CompressionFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 检查是否支持压缩
String acceptEncoding = httpRequest.getHeader("Accept-Encoding");
if (acceptEncoding != null && acceptEncoding.contains("gzip")) {
// 启用压缩
httpResponse.setHeader("Content-Encoding", "gzip");
GZIPOutputStream gzipOut = new GZIPOutputStream(response.getOutputStream());
chain.doFilter(request, new GzipResponseWrapper(httpResponse, gzipOut));
} else {
chain.doFilter(request, response);
}
}
}

3.7 本章小结

关键要点

  1. 请求处理流程

  2. 路由机制

  3. NIO 模型

  4. 性能优化

配置要点

  1. 连接器配置

    • 合理设置线程池参数
    • 优化连接超时和保持时间
    • 启用压缩和缓存
  2. 容器配置

    • 合理设置应用上下文
    • 优化 Servlet 映射
    • 配置过滤器和监听器

下一步学习

在下一章中,我们将深入探讨 Tomcat 的线程模型与运行方式,了解不同 I/O 模式的特点和适用场景,以及如何根据应用需求选择合适的运行模式。


相关资源

http://www.jsqmd.com/news/331895/

相关文章:

  • 合肥靠谱眼科诊所直推!近视矫正/眼健康管理不踩坑
  • 2026年知名的电镀废气处理设备/印刷废气处理设备厂家推荐及选购参考榜
  • 2026高性价比高中辅导机构大盘点!选对不踩坑,提分更高效
  • 2026线上小学补习提分榜|实测8家机构,精准提分不踩坑!
  • 射频工程师所需基础知识简略
  • 2026高性价比线上小学辅导机构精选
  • 2026年评价高的汤面纸碗/一次性纸碗行业内知名厂家推荐
  • MX播放器 2.7.2 |安卓解码最强的媒体播放器
  • PHP 现在可以零成本构建原生 iOS 和 Android 应用 NativePHP for Mobile v3 发布
  • 2026年评价高的喷塑不锈钢扎带/不锈钢扎带厂家推荐与选择指南
  • 2026年评价高的宁波劳保工作服/宁波职业装工作服优质厂家推荐汇总
  • 2026年热门的悬挂式除铁器/强磁除铁器优质供应商推荐参考
  • 2026年质量好的铝天花铝扣板/300300铝扣板厂家选购完整指南
  • 基于Java的高校成绩报送系统(11870)
  • 2026年口碑好的强磁磁选机/磁选机厂家实力与用户口碑参考
  • 基于Java的大学生疫情在校封闭管理系统(11868)
  • 2026年靠谱的珠孔形尼龙扎带/耐高温尼龙扎带厂家推荐与选购指南
  • 基于Java的电影在线购票系统(11869)
  • 基于java的城市交通管理系统(11866)
  • 2026年比较好的酒店办公设计/商业办公设计行业口碑榜
  • 2026年口碑好的民宿设计师/改造民宿设计值得信赖榜
  • 2026年评价高的袖套/PVC袖套厂家推荐与选购指南
  • 2026年知名的布基胶带/胶带厂家选购完整指南
  • 2026年质量好的铝扣板铝天花/冲孔铝天花厂家采购参考指南(必看)
  • OoderA2UI D2C引擎技术原理深度揭秘
  • 2026年比较好的螺旋风管机优质厂家推荐汇总
  • 2026年评价高的型材铝方通/弧形铝方通厂家信誉综合参考
  • 2026年热门的湖北蜈蚣养殖/湖北金头蜈蚣养殖专业推荐榜
  • 2026年国内湖北江南专用特种汽车有限公司/湖北江南行业公信力榜单
  • 2026年AI写论文神器实测:10分钟生成3万字文献综述+真实文献全文引用,这9款工具谁是王者?