CoyoteAdapter-我是沟通的桥梁
在前面说过,由于协议不同,客户端发过来的请求信息也不尽相同,Tomcat 定义了自己的 Request 类来“存放”这些请求信息。ProtocolHandler 接口负责解析请求并生成 Tomcat Request 类。但是这个 Request 对象不是标准的 ServletRequest,也就意味着,不能用 Tomcat Request 作为参数来调用容器。Tomcat 设计者的解决方案是引入 CoyoteAdapter,这是适配器模式的经典运用,连接器调用 CoyoteAdapter 的 Sevice 方法,传入的是 Tomcat Request 对象,CoyoteAdapter 负责将 Tomcat Request 转成 ServletRequest,再调用容器的 Service 方法。
连接器流程图
从图中我们看到,EndPoint 接收到 Socket 连接后,生成一个 SocketProcessor 任务提交到线程池去处理,SocketProcessor 的 Run 方法会调用 Processor 组件去解析应用层协议,Processor 通过解析生成 Request 对象后,会调用 Adapter 的 Service 方法。
Adapter 组件
通过前面Http11Processor解析后,最后调用用service
//获取CoyoteAdapter,调用其service方法
getAdapter().service(request, response);
现在我们主要分析一下Adapter的service源码
public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)
throws Exception {
//org.apache.catalina.connector.Request,实现了javax.servlet.http.HttpServletRequest接口
Request request = (Request) req.getNote(ADAPTER_NOTES);
//org.apache.catalina.connector.Response,实现了javax.servlet.http.HttpServletResponse接口
Response response = (Response) res.getNote(ADAPTER_NOTES);
if (request == null) {
// Create objects
// 创建对象
request = connector.createRequest();
request.setCoyoteRequest(req);
response = connector.createResponse();
response.setCoyoteResponse(res);
// Link objects
request.setResponse(response);
response.setRequest(request);
// Set as notes
req.setNote(ADAPTER_NOTES, request);
res.setNote(ADAPTER_NOTES, response);
// Set query string encoding
// 设置请求编码方式
req.getParameters().setQueryStringCharset(connector.getURICharset());
}
。。。。
try {
// Parse and set Catalina and configuration specific
// request parameters
//解析并设置Catalina和配置特定的请求参数
postParseSuccess = postParseRequest(req, request, res, response);
if (postParseSuccess) {
//check valves if we support async
request.setAsyncSupported(
connector.getService().getContainer().getPipeline().isAsyncSupported());
// Calling the container
//调用容器
// 使用Container去处理请求
// getFirst的返回对象是Valve,在Tomcat初始化的时候存放在容器中
connector.getService().getContainer().getPipeline().getFirst().invoke(
request, response);
。。。。。
总结
Tomcat 的整体架构包含了两个核心组件连接器和容器。连接器负责对外交流,容器负责内部处理。连接器用 ProtocolHandler 接口来封装通信协议和 I/O 模型的差异,ProtocolHandler 内部又分为 EndPoint 和 Processor 模块,EndPoint 负责底层 Socket 通信,Proccesor 负责应用层协议解析。连接器通过适配器 Adapter 调用容器。