日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

Tomcat 处理 HTTP 请求源码分析(上)【转】

發(fā)布時(shí)間:2025/4/5 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Tomcat 处理 HTTP 请求源码分析(上)【转】 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原文地址:https://www.infoq.cn/article/zh-tomcat-http-request-1

很多開(kāi)源應(yīng)用服務(wù)器都是集成 tomcat 作為 web container 的,而且對(duì)于 tomcat 的 servlet container 這部分代碼很少改動(dòng)。這樣,這些應(yīng)用服務(wù)器的性能基本上就取決于 Tomcat 處理 HTTP 請(qǐng)求的 connector 模塊的性能。本文首先從應(yīng)用層次分析了 tomcat 所有的 connector 種類及用法,接著從架構(gòu)上分析了 connector 模塊在整個(gè) tomcat 中所處的位置,最后對(duì) connector 做了詳細(xì)的源代碼分析。并且我們以 Http11NioProtocol 為例詳細(xì)說(shuō)明了 tomcat 是如何通過(guò)實(shí)現(xiàn) ProtocolHandler 接口而構(gòu)建 connector 的。

通過(guò)本文的學(xué)習(xí),應(yīng)該可以輕松做到將 tomcat 做為 web container 集成到第三方系統(tǒng),并且自定義任何你想要的高性能的 HTTP 連接器。

1 Connector 介紹

1.1 Connector 的種類

Tomcat 源碼中與 connector 相關(guān)的類位于 org.apache.coyote 包中,Connector 分為以下幾類:

  • Http Connector, 基于 HTTP 協(xié)議,負(fù)責(zé)建立 HTTP 連接。它又分為 BIO Http Connector 與 NIO Http Connector 兩種,后者提供非阻塞 IO 與長(zhǎng)連接 Comet 支持。
  • AJP Connector, 基于 AJP 協(xié)議,AJP 是專門設(shè)計(jì)用來(lái)為 tomcat 與 http 服務(wù)器之間通信專門定制的協(xié)議,能提供較高的通信速度和效率。如與 Apache 服務(wù)器集成時(shí),采用這個(gè)協(xié)議。
  • APR HTTP Connector, 用 C 實(shí)現(xiàn),通過(guò) JNI 調(diào)用的。主要提升對(duì)靜態(tài)資源(如 HTML、圖片、CSS、JS 等)的訪問(wèn)性能。現(xiàn)在這個(gè)庫(kù)已獨(dú)立出來(lái)可用在任何項(xiàng)目中。Tomcat 在配置 APR 之后性能非常強(qiáng)勁。

1.2 Connector 的配置

對(duì) Connector 的配置位于 conf/server.xml 文件中。

1.2.1 BIO HTTP/1.1 Connector 配置

一個(gè)典型的配置如下:

<Connector port=”8080” protocol=”HTTP/1.1” maxThreads=”150” connectionTimeout=”20000” redirectPort=”8443”

其它一些重要屬性如下:

  • acceptCount : 接受連接 request 的最大連接數(shù)目,默認(rèn)值是 10
  • address : 綁定 IP 地址,如果不綁定,默認(rèn)將綁定任何 IP 地址
  • allowTrace : 如果是 true, 將允許 TRACE HTTP 方法
  • compressibleMimeTypes : 各個(gè) mimeType, 以逗號(hào)分隔,如 text/html,text/xml
  • compression : 如果帶寬有限的話,可以用 GZIP 壓縮
  • connectionTimeout : 超時(shí)時(shí)間,默認(rèn)為 60000ms (60s)
  • maxKeepAliveRequest : 默認(rèn)值是 100
  • maxThreads : 處理請(qǐng)求的 Connector 的線程數(shù)目,默認(rèn)值為 200

如果是 SSL 配置,如下:

<Connector port="8181" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol = "TLS" address="0.0.0.0" keystoreFile="E:/java/jonas-full-5.1.0-RC3/conf/keystore.jks" keystorePass="changeit" />

其中,keystoreFile 為證書位置,keystorePass 為證書密碼

1.2.2 NIO HTTP/1.1 Connector 配置

<Connector port=”8080” protocol=”org.apache.coyote.http11.Http11NioProtocol” maxThreads=”150” connectionTimeout=”20000” redirectPort=”8443”

1.2.3 Native APR Connector 配置

  • ARP 是用 C/C++ 寫的,對(duì)靜態(tài)資源(HTML,圖片等)進(jìn)行了優(yōu)化。所以要下載本地庫(kù)

    tcnative-1.dll 與 openssl.exe,將其放在 %tomcat%\bin 目錄下。

    下載地址是:http://tomcat.heanet.ie/native/1.1.10/binaries/win32/

  • 在 server.xml 中要配置一個(gè) Listener, 如下圖。這個(gè)配置 tomcat 是默認(rèn)配好的。 <!--APR library loader. Documentation at /docs/apr.html --> <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  • 配置使用 APR connector <Connector port=”8080” protocol=”org.apache.coyote.http11.Http11AprProtocol”

    maxThreads=”150” connectionTimeout=”20000” redirectPort=”8443”

  • 如果配置成功,啟動(dòng) tomcat, 會(huì)看到如下信息: org.apache.coyote.http11.Http11AprProtocol init
  • 2 Connector 在 Tomcat 中所處的位置

    2.1 Tomcat 架構(gòu)

    圖 2-1 Tomcat 架構(gòu)

    • Server(服務(wù)器) 是 Tomcat 構(gòu)成的頂級(jí)構(gòu)成元素,所有一切均包含在 Server 中,Server 的實(shí)現(xiàn)類 StandardServer 可以包含一個(gè)到多個(gè) Services;
    • 次頂級(jí)元素 Service 的實(shí)現(xiàn)類為 StandardService 調(diào)用了容器 (Container) 接口,其實(shí)是調(diào)用了 Servlet Engine(引擎),而且 StandardService 類中也指明了該 Service 歸屬的 Server;
    • 接下來(lái)次級(jí)的構(gòu)成元素就是容器 (Container),主機(jī) (Host)、上下文 (Context) 和引擎 (Engine) 均繼承自 Container 接口,所以它們都是容器。但是,它們是有父子關(guān)系的,在主機(jī) (Host)、上下文 (Context) 和引擎 (Engine) 這三類容器中,引擎是頂級(jí)容器,直接包含是主機(jī)容器,而主機(jī)容器又包含上下文容器,所以引擎、主機(jī)和上下文從大小上來(lái)說(shuō)又構(gòu)成父子關(guān)系,雖然它們都繼承自 Container 接口。
    • 連接器 (Connector) 將 Service 和 Container 連接起來(lái),首先它需要注冊(cè)到一個(gè) Service,它的作用就是把來(lái)自客戶端的請(qǐng)求轉(zhuǎn)發(fā)到 Container(容器),這就是它為什么稱作連接器的原因。

    故我們從功能的角度將 Tomcat 源代碼分成 5 個(gè)子模塊,它們分別是:

  • Jsper 子模塊:這個(gè)子模塊負(fù)責(zé) jsp 頁(yè)面的解析、jsp 屬性的驗(yàn)證,同時(shí)也負(fù)責(zé)將 jsp 頁(yè)面動(dòng)態(tài)轉(zhuǎn)換為 java 代碼并編譯成 class 文件。在 Tomcat 源代碼中,凡是屬于 org.apache.jasper 包及其子包中的源代碼都屬于這個(gè)子模塊;
  • Servlet 和 Jsp 規(guī)范的實(shí)現(xiàn)模塊:這個(gè)子模塊的源代碼屬于 javax.servlet 包及其子包,如我們非常熟悉的 javax.servlet.Servlet 接口、javax.servet.http.HttpServlet 類及 javax.servlet.jsp.HttpJspPage 就位于這個(gè)子模塊中;
  • Catalina 子模塊:這個(gè)子模塊包含了所有以 org.apache.catalina 開(kāi)頭的 java 源代碼。該子模塊的任務(wù)是規(guī)范了 Tomcat 的總體架構(gòu),定義了 Server、Service、Host、Connector、Context、Session 及 Cluster 等關(guān)鍵組件及這些組件的實(shí)現(xiàn),這個(gè)子模塊大量運(yùn)用了 Composite 設(shè)計(jì)模式。同時(shí)也規(guī)范了 Catalina 的啟動(dòng)及停止等事件的執(zhí)行流程。從代碼閱讀的角度看,這個(gè)子模塊應(yīng)該是我們閱讀和學(xué)習(xí)的重點(diǎn)。
  • Connectors 子模塊:如果說(shuō)上面三個(gè)子模塊實(shí)現(xiàn)了 Tomcat 應(yīng)用服務(wù)器的話,那么這個(gè)子模塊就是 Web 服務(wù)器的實(shí)現(xiàn)。所謂連接器 (Connector) 就是一個(gè)連接客戶和應(yīng)用服務(wù)器的橋梁,它接收用戶的請(qǐng)求,并把用戶請(qǐng)求包裝成標(biāo)準(zhǔn)的 Http 請(qǐng)求 (包含協(xié)議名稱,請(qǐng)求頭 Head,請(qǐng)求方法是 Get 還是 Post 等等)。同時(shí),這個(gè)子模塊還按照標(biāo)準(zhǔn)的 Http 協(xié)議,負(fù)責(zé)給客戶端發(fā)送響應(yīng)頁(yè)面,比如在請(qǐng)求頁(yè)面未發(fā)現(xiàn)時(shí),connector 就會(huì)給客戶端瀏覽器發(fā)送標(biāo)準(zhǔn)的 Http 404 錯(cuò)誤響應(yīng)頁(yè)面。
  • Resource 子模塊:這個(gè)子模塊包含一些資源文件,如 Server.xml 及 Web.xml 配置文件。嚴(yán)格說(shuō)來(lái),這個(gè)子模塊不包含 java 源代碼,但是它還是 Tomcat 編譯運(yùn)行所必需的。
  • 2.2 Tomcat 運(yùn)行流程

    圖 2-2 tomcat 運(yùn)行流程

    假設(shè)來(lái)自客戶的請(qǐng)求為:http://localhost:8080/test/index.jsp

  • 請(qǐng)求被發(fā)送到本機(jī)端口 8080,被在那里偵聽(tīng)的 Coyote HTTP/1.1 Connector 獲得
  • Connector 把該請(qǐng)求交給它所在的 Service 的 Engine 來(lái)處理,并等待 Engine 的回應(yīng)
  • Engine 獲得請(qǐng)求 localhost:8080/test/index.jsp,匹配它所有虛擬主機(jī) Host
  • Engine 匹配到名為 localhost 的 Host(即使匹配不到也把請(qǐng)求交給該 Host 處理,因?yàn)樵?Host 被定義為該 Engine 的默認(rèn)主機(jī))
  • localhost Host 獲得請(qǐng)求 /test/index.jsp,匹配它所擁有的所有 Context
  • Host 匹配到路徑為 /test 的 Context(如果匹配不到就把該請(qǐng)求交給路徑名為""的 Context 去處理)
  • path="/test"的 Context 獲得請(qǐng)求 /index.jsp,在它的 mapping table 中尋找對(duì)應(yīng)的 servlet
  • Context 匹配到 URL PATTERN 為 *.jsp 的 servlet,對(duì)應(yīng)于 JspServlet 類
  • 構(gòu)造 HttpServletRequest 對(duì)象和 HttpServletResponse 對(duì)象,作為參數(shù)調(diào)用 JspServlet 的 doGet 或 doPost 方法
  • Context 把執(zhí)行完了之后的 HttpServletResponse 對(duì)象返回給 Host
  • Host 把 HttpServletResponse 對(duì)象返回給 Engine
  • Engine 把 HttpServletResponse 對(duì)象返回給 Connector
  • Connector 把 HttpServletResponse 對(duì)象返回給客戶 browser
  • 3 Connector 源碼分析

    3.1 Tomcat 的啟動(dòng)分析與集成設(shè)想

    我們知道,啟動(dòng) tomcat 有兩種方式:

    • 雙擊 bin/startup.bat
    • 運(yùn)行 bin/catalina.bat run

    它們對(duì)應(yīng)于 Bootstrap 與 Catalina 兩個(gè)類,我們現(xiàn)在只關(guān)心 Catalina 這個(gè)類,這個(gè)類使用 Apache Digester 解析 conf/server.xml 文件生成 tomcat 組件,然后再調(diào)用 Embedded 類的 start 方法啟動(dòng) tomcat。

    所以,集成 Tomcat 的方式就有以下兩種了:

    • 沿用 tomcat 自身的 server.xml
    • 自己定義一個(gè) xml 格式來(lái)配置 tocmat 的各參數(shù),自己再寫解析這段 xml,然后使用 tomcat 提供的 API 根據(jù)這些 xml 來(lái)生成 Tomcat 組件,最后調(diào)用 Embedded 類的 start 方法啟動(dòng) tomcat

    個(gè)人覺(jué)得第一種方式要優(yōu)越,給開(kāi)發(fā)者比較好的用戶體驗(yàn),如果使用這種,直接模仿 Catalina 類的方法即可實(shí)現(xiàn)集成。

    目前,JOnAS 就使用了這種集成方式,JBoss、GlassFish 使用的第二種自定義 XML 的方式。

    3.2 Connector 類圖與順序圖

    圖 3-1 Connector 相關(guān)類圖

    圖 3-2 Connector 工作流程順序圖

    從上面二圖中我們可以得到如下信息:

  • Tomcat 中有四種容器 (Context、Engine、Host、Wrapper),前三者常見(jiàn),第四個(gè)不常見(jiàn)但它也是實(shí)現(xiàn)了 Container 接口的容器
  • 如果要自定義一個(gè) Connector 的話,只需要實(shí)現(xiàn) ProtocolHander 接口, 該接口定義如下:
  • 圖 3-3 自定義 connector 時(shí)需實(shí)現(xiàn)的 ProtocolHandler 接口

    Tomcat 以 HTTP(包括 BIO 與 NIO)、AJP、APR、內(nèi)存四種協(xié)議實(shí)現(xiàn)了該接口(它們分別是:AjpAprProtocol、AjpProtocol、Http11AprProtocol、Http11NioProtocol、Http11Protocal、JkCoyoteHandler、MemoryProtocolHandler),要使用哪種 Connector 就在 conf/server.xml 中配置,在 Connector 的構(gòu)造函數(shù)中會(huì)通過(guò)反射實(shí)例化所配置的實(shí)現(xiàn)類:

    <Connector port="8181" protocol="org.apache.coyote.http11.Http11AprProtocol " />

    3.3 Connector 的工作流程

    下面我們以 Http11AprProtocol 為例說(shuō)明 Connector 的工作流程。

  • 它將工作委托給 NioEndpoint 類。在 NioEndpoint 類的 init 方法中構(gòu)建一個(gè) SocketServer(當(dāng)然,不同的實(shí)現(xiàn)類會(huì)有一些微小的變化,例如如果是 NIO,它構(gòu)建的就是 SocketServerChannel)
  • 在 NioEndpoint.Acceptor 類中會(huì)接收一個(gè)客戶端新的連接請(qǐng)求,如下圖:

  • 在 NioEndpoint 類中,有一個(gè)內(nèi)部接口 Handle,該接口定義如下:

  • 在 Http11NioProtocol 類中實(shí)現(xiàn)了 Handle 這個(gè)內(nèi)部接口,并調(diào)用 Http11NioProcessor 類 (該類實(shí)現(xiàn)了 ActionHook 回調(diào)接口)。在 Response 類中會(huì)調(diào)用 ActionHook 實(shí)現(xiàn)類的相關(guān)方法的,Response 類的 action 方法如下:

  • Http11NioProcessor 的 process 實(shí)現(xiàn)方法中,會(huì)通過(guò) Adapter 來(lái)調(diào)用 Servler 容器生成響應(yīng)結(jié)果。
  • 轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/articles/11249466.html

    總結(jié)

    以上是生活随笔為你收集整理的Tomcat 处理 HTTP 请求源码分析(上)【转】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。