Tomcat 第四篇:请求处理流程(上)

Tomcat 第四篇:请求处理流程(上)

1. 引言

既然是在讲 Tomcat ,那么一个 HTTP 请求请求流程是无论如何也绕不开的。

首先抛开所有,使用我们现有的知识面,猜测一下一个请求被 Tomcat 处理的过程:

1. 客户端(浏览器)发送一个请求(HTTP) 2. 建立 Socket 连接 3. 通过 Socket 读取数据 4. 根据协议(HTTP)解析请求 5. 调用对应的代码完成响应

上面这套流程,我相信任何一个 Java 码农都能想得到,当 Tomcat 接受到请求后,经过一系列的基础处理,最终会调用到我们自己的业务程序上,或者说是 Servlet 上,在早期,这些请求会由我们自己实现的 jsp 或者是 Servlet 进行接收,随着时代的发展以及演进,出现了 Struts 和 Spring 等中间件来帮助我们完成基础的请求处理,使得开发人员更加关注具体的业务。

我想很多人都很好奇, Tomcat 是如何将这些 HTTP 请求转交给我们的 Servlet 的?

2. Connector 初始化

上一篇我们在聊 Tomcat 启动流程的时候,最后执行初始化的是 org.apache.catalina.connector.Connector#initInternal() ,这时整个初始化流程到了 Connector ,看一下这段代码:

// 去除部分代码 protected void initInternal() throws LifecycleException { super.initInternal(); // Initialize adapter adapter = new CoyoteAdapter(this); protocolHandler.setAdapter(adapter); // ...... try { protocolHandler.init(); } catch (Exception e) { throw new LifecycleException( sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e); } }

这段代码中主要做了两件事情:

构造了 CoyoteAdapter 对象,并且将其设置为 ProtocolHandler 的 Adapter 。

调用了 org.apache.coyote.ProtocolHandler#init() 的方法。

先说第二件事情,调用了 org.apache.coyote.ProtocolHandler#init() ,ProtocolHandler 是在构造方法中进行的初始化,这里的核心代码是:

setProtocol(protocol)

再看下 setProtocol() 这个方法做了啥:

public void setProtocol(String protocol) { boolean aprConnector = AprLifecycleListener.isAprAvailable() && AprLifecycleListener.getUseAprConnector(); if ("HTTP/1.1".equals(protocol) || protocol == null) { if (aprConnector) { setProtocolHandlerClassName("org.apache.coyote.http11.Http11AprProtocol"); } else { setProtocolHandlerClassName("org.apache.coyote.http11.Http11NioProtocol"); } } else if ("AJP/1.3".equals(protocol)) { if (aprConnector) { setProtocolHandlerClassName("org.apache.coyote.ajp.AjpAprProtocol"); } else { setProtocolHandlerClassName("org.apache.coyote.ajp.AjpNioProtocol"); } } else { setProtocolHandlerClassName(protocol); } }

看到这里可以知道,主逻辑分成了两块,一块是使用 HTTP/1.1 协议,另一块是使用了 AJP/1.3 的协议,这里通过协议的不同,最终初始化了不同的类。

如果是使用 HTTP/1.1 的协议,则采用了 org.apache.coyote.http11.Http11AprProtocol 或者 org.apache.coyote.http11.Http11NioProtocol,如果是采用 AJP/1.3 则采用 org.apache.coyote.ajp.AjpAprProtocol 或者是 org.apache.coyote.ajp.AjpNioProtocol 。

看下 org.apache.coyote.http11.Http11AprProtocol 和 org.apache.coyote.ajp.AjpAprProtocol 继承关系图:

Tomcat 第四篇:请求处理流程(上)

Tomcat 第四篇:请求处理流程(上)

可以看到这两个类都继承自 org.apache.coyote.AbstractProtocol ,通过查看 org.apache.coyote.AbstractProtocol#init() 方法,可以看到是调用了 org.apache.tomcat.util.net.AbstractEndpoint#init() ,而 AbstractEndpoint 的实例化操作是在实例化 AjpProtocol 和 Http11Protocol 的时候在其构造函数中实例化的,而在 AjpProtocol 和 Http11Protocol 的构造函数中,实际上是都初始化了 org.apache.tomcat.util.net.JIoEndpoint ,只不过根据不同的 HTTP 或者是 AJP 协议,它们具有不同的连接处理类。其中 Http11Protocol 的连接处理类为 org.apache.coyote.http11.Http11Protocol.Http11ConnectionHandler ,而连接处理类为 org.apache.coyote.ajp.AjpProtocol.AjpConnectionHandler 。

除此之外, ProtocolHandler 还有其他实现,都在 org.apache.coyote 这个包中,一些常见的类图如下:

Tomcat 第四篇:请求处理流程(上)

因此到这里我们基本清楚了 Connector 的初始化流程,总结如下:

//1 HTTP/1.1协议连接器 org.apache.catalina.connector.Connector#init ->org.apache.coyote.http11.Http11AprProtocol#init -->org.apache.tomcat.util.net.AprEndpoint#init (org.apache.coyote.http11.Http11AprProtocol.Http11ConnectionHandler) // 2 AJP/1.3协议连接器 org.apache.catalina.connector.Connector#init ->org.apache.coyote.ajp.AjpAprProtocol#init -->org.apache.tomcat.util.net.AprEndpoint#init (org.apache.coyote.ajp.AjpAprProtocol.AjpConnectionHandler) 3. Connector 启动

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyjfgw.html