深刻拆解Tomcat & Jetty-學習筆記(2)模塊二之tomcat系統架構

總體架構

概述

咱們知道若是要設計一個系統,首先是要了解需求。 Tomcat 要實現 2 個核心功能:nginx

  1. 處理 Socket 鏈接,負責網絡字節流與 Request 和 Response 對象的轉化。
  2. 加載和管理 Servlet,以及具體處理 Request 請求。 所以 Tomcat 設計了兩個核心組件鏈接器(Connector)和容器(Container)來分別作這兩件事情。鏈接器負責對外交流,容器負責內部處理。

從圖上你能夠看到,最頂層是 Server,這裏的 Server 指的就是一個 Tomcat 實例。一個 Server 中有一個或者多個 Service,一個 Service 中有多個鏈接器和一個容器。鏈接器與容器之間經過標準的 ServletRequest 和 ServletResponse 通訊。web

鏈接器的設計

什麼是鏈接器

鏈接器對 Servlet 容器屏蔽了協議及 I/O 模型等的區別,不管是 HTTP 仍是 AJP,在容器中獲取到的都是一個標準的 ServletRequest 對象。apache

鏈接器的功能細化

監聽網絡端口。 接受網絡鏈接請求。 讀取網絡請求字節流。 根據具體應用層協議(HTTP/AJP)解析字節流,生成統一的 Tomcat Request 對象。 將 Tomcat Request 對象轉成標準的 ServletRequest。 調用 Servlet 容器,獲得 ServletResponse。 將 ServletResponse 轉成 Tomcat Response 對象。 將 Tomcat Response 轉成網絡字節流。 將響應字節流寫回給瀏覽器。瀏覽器

鏈接器的子模塊

經過分析鏈接器的詳細功能列表,咱們發現鏈接器須要完成 3 個高內聚的功能:tomcat

  • 網絡通訊。
  • 應用層協議解析。
  • Tomcat Request/Response 與 ServletRequest/ServletResponse 的轉化。 這個三個功能對應了組件來完成其功能:
  • endpoint :是通訊端點,對傳輸層的抽象,它能夠有不一樣的I/O模型的實現 如非阻塞 I/O、異步 I/O 或者 APR
  • processor :Processor 用來實現 HTTP 協議,Processor 接收來自 Endpoint 的 Socket,讀取字節流解析成 Tomcat Request 和 Response 對象,並經過 Adapter 將其提交到容器處理,Processor 是對應用層協議的抽象。這一層能夠有Http協議的變化,如 HTTP、HTTPS、AJP
  • adapter

ProtocolHandler 組件

ProtocolHandler 組件是將EndPoint和Processor兩個組件進行了封裝 下圖爲兩個維度不一樣的組合網絡

鏈接器組件圖

Endpoint 接收到 Socket 鏈接後, 生成一個 SocketProcessor 任務提交到線程池去處理, SocketProcessor 的 run 方法會調用 Processor 組件去解析應用層協議, Processor 經過解析生成 Request 對象後, 會調用 Adapter 的 Service 方法。架構

Adapter 組件

Adapter 組件完成 Tomcat Request ->Servlet Request的轉換 CoyoteAdapter 負責將 Tomcat Request 轉成 ServletRequest,再調用容器的 service 方法。app

爲何要多一層adapter?

問題:在processor直接轉換爲容器的servletrequest和servletresponse不是更好,爲何要先轉化Tomcat的request和response,再用adapter作一層轉換消耗性能?異步

回答:若是鏈接器直接建立ServletRequest和ServletResponse對象的話,就和Servlet協議耦合了,設計者認爲鏈接器儘可能保持獨立性,它不必定要跟Servlet容器工做的。另外對象轉化的性能消耗仍是比較少的,Tomcat對HTTP請求體採起了延遲解析的策略,也就是說,TomcatRequest對象轉化成ServletRequest的時候,請求體的內容都還沒讀取呢,直到容器處理這個請求的時候纔讀取的。性能

tomcat和nginx的性能差別出現的緣由?
  1. Nginx/Apche通常作反向代理和處理靜態HTML資源,作的事情相對來講簡單,KPI就是要快,所以用C語言實現,直接調用操做系統API,充分利用操做系統的高級特性。

  2. 而Tomcat用來處理動態請求,還須要跑Java應用,所以用Java實現,所以」快「不是它主要的KPI。Java調用操做系統API要經過JNI,無形中有性能損耗。另外Tomcat經過使用Apache APR本地庫來作I/O通訊,性能已經跟Apache、Nginx接近了。

同一個tomcat能夠設置多個端口號來啓動多個應用嗎?

能夠的,在server.xml配置多個service,或者同一個service裏配置多個connector

多層容器的設計

容器的層次結構

omcat 設計了 4 種容器,分別是 Engine、Host、Context 和 Wrapper。

一個 Tomcat 實例包含一個service 一個 Service 包含一個 Engine和多個鏈接器, 一個 Engine 包含多個 Host, 一個 Host包 含多個Context 一個 Context包含多個 Wrapper 一個 Wrapper包含一個servlet

請求定位 Servlet 的過程

  • 由 Mapper 組件完成, Mapper 組件保存了容器組件與訪問路徑的映射關係, 根據請求的 URL 進行定位

    • 端口號定位出 Service 和 Engine
    • 域名定位出 Host
    • URL 路徑定位出 Context Web 應用
    • URL 路徑定位出 Wrapper ( Servlet )
  • 在各個層次定位過程當中, 都會對請求作一些處理

    • 經過 Pipeline-Valve 實現容器間的互相調用 ( 責任鏈模式 )
    • valve 表示一個處理點 ( 如權限認證, 日誌等), 處理請求; valve 經過鏈表串聯, 並由 pipeline 維護
    • valve 會經過 getNext().invoke() 調用下一個 valve, 最後一個 valve ( Basic ) 調用下一層容器的 pipeline 的第一個 valve
    • Adapter 調用 Engine pipeline 的第一個 valve
    • Wrapper 最後一個 valve 會建立一個 Filter 鏈, 並最終調用 Servlet 的 service 方法

  • valve 與 filter 對比
    • valve 是 Tomcat 的私有機制, Filter 是 Servlet API 公有標準
    • valve 工做在容器級別, 攔截全部應用; Servlet Filter 工做在應用級別, 只能攔截某個應用的請求
Tomcat 內的 Context 組件跟 Servlet 規範中的 ServletContext 接口有什麼區別?跟 Spring 中的 ApplicationContext 又有什麼關係?
  • Servlet規範中ServletContext表示web應用的上下文環境,而web應用對應tomcat的概念是Context,因此從設計上,ServletContext天然會成爲tomcat的Context具體實現的一個成員變量
  • tomcat內部實現也是這樣完成的,ServletContext對應tomcat實現是org.apache.catalina.core.ApplicationContext,Context容器對應tomcat實現是org.apache.catalina.core.StandardContext。ApplicationContext是StandardContext的一個成員變量。
  • Spring的ApplicationContext以前已經介紹過,tomcat啓動過程當中ContextLoaderListener會監聽到容器初始化事件,它的contextInitialized方法中,Spring會初始化全局的Spring根容器ApplicationContext,初始化完畢後,Spring將其存儲到ServletContext中。總而言之,Servlet規範中ServletContext是tomcat的Context實現的一個成員變量,而Spring的ApplicationContext是Servlet規範中ServletContext的一個屬性。
Basic valve 有些疑惑。好比engine容器下有多個host容器,那engine容器的basic valve是怎麼知道要指向哪一個host容器的value呢?

Mapper組件在映射請求的時候,會在Request對象中存儲相應的Host、Context等對象,這些選定的容器用來處理這個特定的請求,所以Engine中的Valve是從Request對象拿到Host容器的。

生產環境中, 配的都是一個 tomcat 對應一個應用, 多個應用就用多個tomcat ,它和一個 tomcat 加載多個應用有什麼區別麼?

在同一個Tomcat實例裏部署多個Web應用是爲了節省內存等資源,不過配置部署有點複雜,應用之間互相影響,加上如今硬件成本將低,多應用部署比較少見了。

備註

本文是我我的學習了李號雙老師的專欄課程以後,結合專欄文章和老師對同窗答疑整理的學習筆記。僅供分享。更多精彩內容,你們能夠掃描下方二位碼,在極客時間訂閱李號雙老師的《深刻拆解Tomcat & Jetty》。獲取一手學習資料。

相關文章
相關標籤/搜索