一、Http工作原理
????????HTTP協議是瀏覽器與服務器之間的數據傳送協議。作為應用層協議,HTTP是基于TCP/IP協議來傳遞數據的(HTML文件、圖片、查詢結果等),HTTP協議不涉及數據包(Packet)傳輸,主要規定了客戶端和服務器之間的通信格式。
從圖上你可以看到,這個過程是:
1) 用戶通過瀏覽器進行了一個操作,比如輸入網址并回車,或者是點擊鏈接,接著瀏覽器獲取了這個事件。
2) 瀏覽器向服務端發出TCP連接請求。
3) 服務程序接受瀏覽器的連接請求,并經過TCP三次握手建立連接。
4) 瀏覽器將請求數據打包成一個HTTP協議格式的數據包。
5) 瀏覽器將該數據包推入網絡,數據包經過網絡傳輸,最終達到端服務程序。
6) 服務端程序拿到這個數據包后,同樣以HTTP協議格式解包,獲取到客戶端的意圖。
7) 得知客戶端意圖后進行處理,比如提供靜態文件或者調用服務端程序獲得動態結果。
8) 服務器將響應結果(可能是HTML或者圖片等)按照HTTP協議格式打包。
9) 服務器將響應數據包推入網絡,數據包經過網絡傳輸最終達到到瀏覽器。
10) 瀏覽器拿到數據包后,以HTTP協議的格式解包,然后解析數據,假設這里的數據是HTML。
11) 瀏覽器將HTML文件展示在頁面上。
在這個過程中都做了些什么事情呢?主要是接受連接、解析請求數據、處理請求和發送響應這幾個步驟。
二、Tomcat的整體架構
????????1.Http服務器請求處理
????????瀏覽器發給服務端的是一個HTTP格式的請求,HTTP服務器收到這個請求后,需要調用服務端程序來處理,所謂的服務端程序就是你寫的Java類,一般來說不同的請求需要由不同的Java類來處理。
????????圖1,表示HTTP服務器直接調用具體業務類,它們是緊耦合的。
????????圖2,HTTP服務器不直接調用業務類,而是把請求交給容器來處理,容器通過Servlet接口調用業務類。因此Servlet接口和Servlet容器的出現,達到了HTTP服務器與業務類解耦的目的。而Servlet接口和Servlet容器這一整套規范叫作Servlet規范。Tomcat按照Servlet規范的要求實現了Servlet容器,同時它們也具有HTTP服務器的功能。作為Java程序員,如果我們要實現新的業務功能,只需要實現一個Servlet,并把它注冊到Tomcat(Servlet容器)中,剩下的事情就由Tomcat幫我們處理了。
????????2.Servlet容器工作流程
????????為了解耦,HTTP服務器不直接調用Servlet,而是把請求交給Servlet容器來處理,那Servlet容器又是怎么工作的呢?
????????當客戶請求某個資源時,HTTP服務器會用一個ServletRequest對象把客戶的請求信息封裝起來,然后調用Servlet容器的service方法,Servlet容器拿到請求后,根據請求的URL和Servlet的映射關系,找到相應的Servlet,如果Servlet還沒有被加載,就用反射機制創建這個Servlet,并調用Servlet的init方法來完成初始化,接著調用Servlet的service方法來處理請求,把ServletResponse對象返回給HTTP服務器,HTTP服務器會把響應發送給客戶端。
????????3.Tomcat整體架構
????????我們知道如果要設計一個系統,首先是要了解需求,我們已經了解了Tomcat要實現兩個核心功能:
????????處理Socket連接,負責網絡字節流與Request和Response對象的轉化。
????????加載和管理Servlet,以及具體處理Request請求。
????????因此Tomcat設計了兩個核心組件連接器(Connector)和容器(Container)來分別做這兩件事情。連接器負責對外交流,容器負責內部處理。
三、連接器 - Coyote
????????1.架構介紹
????????Coyote 是Tomcat的連接器框架的名稱, 是Tomcat服務器提供的供客戶端訪問的外部接口。客戶端通過Coyote與服務器建立連接、發送請求并接受響應 。
????????Coyote 封裝了底層的網絡通信(Socket 請求及響應處理),為Catalina 容器提供了統一的接口,使Catalina 容器與具體的請求協議及IO操作方式完全解耦。Coyote 將Socket輸入轉換封裝為Request對象,交由Catalina 容器進行處理,處理請求完成后, Catalina 通過Coyote 提供的Response 對象將結果寫入輸出流 。
????????Coyote 作為獨立的模塊,只負責具體協議和IO的相關操作,與Servlet規范實現沒有直接關系,因此即便是Request和Response對象也并未實現Servlet規范對應的接口, 而是在Catalina 中將他們進一步封裝為ServletRequest 和 ServletResponse 。
????????2.I/O模型與協議
????????在Coyote中,Tomcat支持的多種I/O模型和應用層協議,具體包含哪些I/O模型和應用層協議,請看下表:
????????Tomcat支持的IO模型(自8.5/9.0版本起,Tomcat移除了對 BIO的支持):
????????Tomcat支持的應用層協議:
????????協議分層:
????????在 8.0 之前 , Tomcat 默認采用的I/O方式為 BIO , 之后改為 NIO。 無論 NIO、NIO2還是 APR, 在性能方面均優于以往的BIO。 如果采用APR, 甚至可以達到 Apache HTTP Server 的影響性能。
????????Tomcat為了實現支持多種I/O模型和應用層協議,一個容器可能對接多個連接器,就好比一個房間有多個門。但是單獨的連接器或者容器都不能對外提供服務,需要把它們組裝起來才能工作,組裝后這個整體叫作Service組件。這里請你注意,Service本身沒有做什么重要的事情,只是在連接器和容器外面多包了一層,把它們組裝在一起。Tomcat內可能有多個Service,這樣的設計也是出于靈活性的考慮。通過在Tomcat中配置多個Service,可以實現通過不同的端口號來訪問同一臺機器上部署的不同應用。
????????3.連接器組件
????????連接器中的各個組件的作用如下:
????????EndPoint
????????1) EndPoint : Coyote 通信端點,即通信監聽的接口,是具體Socket接收和發送處理器,是對傳輸層的抽象,因此EndPoint用來實現TCP/IP協議的。
????????2) Tomcat 并沒有EndPoint 接口,而是提供了一個抽象類AbstractEndpoint,里面定義了兩個內部類:Acceptor和SocketProcessor。Acceptor用于監聽Socket連接請求。SocketProcessor用于處理接收到的Socket請求,它實現Runnable接口,在Run方法里調用協議處理組件Processor進行處理。為了提高處理能力,SocketProcessor被提交到線程池來執行。而這個線程池叫作執行器(Executor)。
????????Processor
????????Processor : Coyote 協議處理接口 ,如果說EndPoint是用來實現TCP/IP協議的,那么Processor用來實現HTTP協議,Processor接收來自EndPoint的Socket,讀取字節流解析成Tomcat Request和Response對象,并通過Adapter將其提交到容器處理,Processor是對應用層協議的抽象。
????????ProtocolHandler
????????ProtocolHandler: Coyote協議接口,通過Endpoint和Processor,實現針對具體協議的處理能力。
????????Tomcat 按照協議和I/O 提供了6個實現類 : AjpNioProtocol、AjpAprProtocol、AjpNio2Protocol、Http11NioProtocol、Http11Nio2Protocol、Http11AprProtocol。
????????我們在配置tomcat/conf/server.xml時,至少要指定具體的ProtocolHandler,當然也可以指定協議名稱,如:HTTP/1.1 ,如果安裝了APR,那么將使用Http11AprProtocol,否則使用 Http11NioProtocol。
????????Adapter
????????由于協議不同,客戶端發過來的請求信息也不盡相同,Tomcat定義了自己的Request類來“存放”這些請求信息。ProtocolHandler接口負責解析請求并生成Tomcat Request類。但是這個Request對象不是標準的ServletRequest,也就意味著,不能用Tomcat Request作為參數來調用容器。Tomcat設計者的解決方案是引入CoyoteAdapter,這是適配器模式的經典運用,連接器調用CoyoteAdapter的Sevice方法,傳入的是TomcatRequest對象,CoyoteAdapter負責將Tomcat Request轉成ServletRequest,再調用容器的Service方法。
四、容器 - Catalina
????????Tomcat是一個由一系列可配置的組件構成的Web容器,而Catalina是Tomcat的servlet容器。
????????Catalina 是Servlet 容器實現,包含了之前講到的所有的容器組件,以及后續章節涉及到的安全、會話、集群、管理等Servlet 容器架構的各個方面。它通過松耦合的方式集成Coyote,以完成按照請求協議進行數據讀寫。同時,它還包括我們的啟動入口、Shell程序等。
????????1.Catalina 地位
????????Tomcat的模塊分層結構圖,如下:
????????Tomcat 本質上就是一款 Servlet 容器,因此Catalina 才是Tomcat 的核心,其他模塊都是為Catalina 提供支撐的。比如 :通過Coyote 模塊提供鏈接通信,Jasper 模塊提供JSP引擎,Naming 提供JNDI 服務,Juli 提供日志服務。
????????2.Catalina 結構
????????Catalina 的主要組件結構如下:
????????如上圖所示,Catalina負責管理Server,而Server表示著整個服務器。Server下面有多個服務Service,每個服務都包含著多個連接器組件Connector(Coyote 實現)和一個容器組件Container。在Tomcat 啟動的時候, 會初始化一個Catalina的實例。
????????Catalina 各個組件的職責:
????????3.Container 結構
????????Tomcat設計了4種容器,分別是Engine、Host、Context和Wrapper。這4種容器不是平行關系,而是父子關系。, Tomcat通過一種分層的架構,使得Servlet容器具有很好的靈活性。
????????各個組件的含義 :
????????我們也可以再通過Tomcat的server.xml配置文件來加深對Tomcat容器的理解。Tomcat采用了組件化的設計,它的構成組件都是可配置的,其中最外層的是Server,其他組件按照一定的格式要求配置在這個頂層容器中。
????????那么,Tomcat是怎么管理這些容器的呢?你會發現這些容器具有父子關系,形成一個樹形結構,你可能馬上就想到了設計模式中的組合模式。沒錯,Tomcat就是用組合模式來管理這些容器的。具體實現方法是,所有容器組件都實現了Container接口,因此組合模式可以使得用戶對單容器對象和組合容器對象的使用具有一致性。這里單容器對象指的是最底層的Wrapper,組合容器對象指的是上面的Context、Host或者Engine。
????????Container 接口中提供了以下方法(截圖中知識一部分方法):
????????在上面的接口看到了getParent、SetParent、addChild和removeChild等方法。
????????Container接口擴展了LifeCycle接口,LifeCycle接口用來統一管理各組件的生命周期。