⚙️ 第三章:Tomcat 请求处理原理
目录
- [3.1 请求到达与解析](#3.1 请求到达与解析)
- [3.2 请求分发机制](#3.2 请求分发机制)
- [3.3 NIO 事件循环模型](#3.3 NIO 事件循环模型)
- [3.4 请求处理详细流程](#3.4 请求处理详细流程)
- [3.5 响应生成与返回](#3.5 响应生成与返回)
- [3.6 性能优化要点](#3.6 性能优化要点)
- [3.7 本章小结](#3.7 本章小结)
3.1 请求到达与解析
3.1.1 请求到达流程
整体流程图
客户端HTTP请求 网络层接收 Connector监听端口 协议解析 CoyoteAdapter适配 Request对象创建 Engine路由 Host匹配 Context匹配 Wrapper匹配 Servlet调用
详细步骤说明
1. 网络层接收
java
// NIO 连接器接收请求
public class Http11NioProtocol extends AbstractHttp11Protocol<NioChannel> {
@Override
protected AbstractEndpoint.Handler<NioChannel> getHandler() {
return new Http11ConnectionHandler(this);
}
}
2. 协议解析
java
// 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 适配
java
// 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 请求解析
java
// 请求行解析
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;
}
}
请求头解析
java
// 请求头解析
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
java
// 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
java
// 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
java
// 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
java
// 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 配置
xml
<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 配置
xml
<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 线程
java
// Acceptor 线程
public class Acceptor<U> extends AbstractEndpoint.Acceptor<U> {
@Override
public void run() {
while (endpoint.isRunning()) {
try {
// 1. 接受连接
SocketChannel socket = serverSock.accept();
// 2. 设置非阻塞模式
socket.configureBlocking(false);
// 3. 注册到 Poller
getPoller0().register(socket);
} catch (Exception e) {
// 处理异常
}
}
}
}
2. Poller 线程
java
// 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 线程池
java
// 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 事件处理流程
详细处理步骤
java
// 请求处理流程
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. 请求接收
java
// 连接器接收请求
public class Http11NioProtocol extends AbstractHttp11Protocol<NioChannel> {
@Override
protected AbstractEndpoint.Handler<NioChannel> getHandler() {
return new Http11ConnectionHandler(this);
}
}
// 连接处理器
public class Http11ConnectionHandler extends AbstractConnectionHandler<NioChannel,Http11NioProcessor> {
@Override
protected Http11NioProcessor createProcessor() {
Http11NioProcessor processor = new Http11NioProcessor(this);
processor.setAdapter(getAdapter());
return processor;
}
}
2. 请求解析
java
// 请求解析器
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. 请求路由
java
// 请求路由
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 调用
java
// 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. 响应头设置
java
// 响应头设置
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. 响应体写入
java
// 响应体写入
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. 连接管理
java
// 连接管理
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 连接优化
连接池配置
xml
<!-- 连接器优化配置 -->
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
maxThreads="200"
minSpareThreads="10"
maxSpareThreads="50"
acceptCount="100"
maxConnections="8192"
keepAliveTimeout="60000"
maxKeepAliveRequests="100" />
线程池优化
java
// 线程池配置
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 缓冲区优化
输入缓冲区
java
// 输入缓冲区配置
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;
}
}
输出缓冲区
java
// 输出缓冲区配置
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 压缩
xml
<!-- 启用压缩 -->
<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" />
压缩实现
java
// 压缩实现
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 本章小结
关键要点
-
请求处理流程:
- 网络层接收 → 协议解析 → 适配器转换 → 容器路由 → Servlet 调用
- 每个步骤都有明确的职责和接口定义
-
路由机制:
- Engine → Host → Context → Wrapper → Servlet
- 每层都有对应的路由逻辑和匹配规则
-
NIO 模型:
- Acceptor 线程接收连接
- Poller 线程处理 I/O 事件
- Worker 线程池处理业务逻辑
-
性能优化:
- 连接池和线程池配置
- 缓冲区大小优化
- 压缩和缓存策略
配置要点
-
连接器配置:
- 合理设置线程池参数
- 优化连接超时和保持时间
- 启用压缩和缓存
-
容器配置:
- 合理设置应用上下文
- 优化 Servlet 映射
- 配置过滤器和监听器
下一步学习
在下一章中,我们将深入探讨 Tomcat 的线程模型与运行方式,了解不同 I/O 模式的特点和适用场景,以及如何根据应用需求选择合适的运行模式。
相关资源: