Tomcat的实现原理
Tomcat 是一個Web容器。作為 Web 應(yīng)用的容器承載著 Web 請求處理和響應(yīng)的工作
最開始用戶通過瀏覽器查看諸如新聞之類的靜態(tài)資源,此時就需要通過 HTTP 服務(wù)器向瀏覽器返回靜態(tài) HTML 資源,瀏覽器將解析的 HTML 呈現(xiàn)給使用者。這里的 Web 容器就是用來存放 HTTP 服務(wù)器,能夠處理網(wǎng)絡(luò)請求并且進行響應(yīng)。
隨著互聯(lián)網(wǎng)的發(fā)展,用戶需求從靜態(tài)資源轉(zhuǎn)向了動態(tài)資源的獲取,同時瀏覽器在資源獲取的同時還會與服務(wù)端進行一些交互。
由此 Web 容器的功能開始有了擴展,除了能夠處理 HTTP 請求,還需要 HTTP 服務(wù)器調(diào)用服務(wù)端程序也就是常說的 Web 應(yīng)用。
針對這種需求,Sun 公司推出了 Servlet 技術(shù), Servlet 是運行在服務(wù)端的 Java 小程序。
由于 Servlet 不能獨立運行,因此需要由一個 Servlet 容器來承載它,并且對其進行初始化啟動等管理操作。
為了承載 Servlet,也加入了 Servlet 容器,不過每個 Servlet 都代表一個業(yè)務(wù)類,包含了一些業(yè)務(wù)應(yīng)用如果都接入到 Web 容器中會用戶提供統(tǒng)一的服務(wù)響應(yīng)就需要遵循統(tǒng)一的接口。
說白了就是要遵守一定規(guī)則才能放到 Servlet 容器中,方便進行管理,那么這個規(guī)則就是 Servlet 接口。從圖中可以看出 Servlet 接口會對單個的 Servlet 進行標準定義。
對于Tomcat而言,它并不知道我們會有什么樣的方法,這些都只是在項目被部署進webapp下后才確定的,由此分析,必然用到了Java的反射來實現(xiàn)類的動態(tài)加載、實例化、獲取方法、調(diào)用方法。但是我們部署到Tomcat的中的Web項目必須是按照規(guī)定好的Servlet 接口來進行編寫,以便進行調(diào)用
public interface Servlet {public void init(ServletConfig config) throws ServletException;public ServletConfig getServletConfig();public void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;public String getServletInfo();public void destroy(); }對于 Servlet 接口而言定義了 init 方法用做 Servlet 資源的初始化,同時也定義 destroy 方法用做 Servlet 資源的釋放。
其中 Service 方法用來實現(xiàn)具體的業(yè)務(wù)需求,可以看到該方法傳入 ServletRequest 和 ServletResponse 兩個參數(shù),分別表示封裝了用戶的請求信息和 Servlet 的響應(yīng)信息。
接口中的 getServletConfig 方法會返回 ServletConfig,ServletConfig 是用來封裝 Servlet 的初始化參數(shù)的,可以在 web.xml 配置 Servlet 參數(shù),然后通過 getServletConfig 方法獲取參數(shù)。
上面介紹了 Servlet 接口一下,再通過圖 5 對 Servlet 接口調(diào)用的周邊類進行深入了解。
如圖 5 所示,Servlet 接口依賴 ServletConfig 接口,該接口正好是用來處理 Servlet 配置參數(shù)的,ServletConfig 接口同時也會關(guān)聯(lián) ServletContext 獲取 Servlet 上下文的信息。
Servlet 接口中的 service 方法依賴兩個參數(shù)分別是 ServletRequest 和 ServletResponse。
同時有兩個接口 HttpServletRequest 和 HttpServletResponse 會分別繼承 ServletRequest 和 ServletResponse。
一般而言 Servlet 作為接口需要具體的實現(xiàn)類去實現(xiàn)這個接口,因此 Servlet 規(guī)范提供了一個抽象類名叫 GenericServlet,它實現(xiàn)了 Servlet。
接著有一個 HttpServlet 的類繼承 GenericServlet,為了處理 HTTP 請求這類也會依賴 HttpServletRequest 和 HttpServletResponse。
Servlet 接口定義是 Servlet 容器的重要組成部分,Servlet 容器通過接口去管理接入的 Servlet 實體。
在了解 Servlet 接口規(guī)范和 Servlet 容器以后,我們知道如果需要加載不同的動態(tài)資源(Web 應(yīng)用)需要利用 Servlet 容器去加載對應(yīng)的 Servlet,那么這個加載過程是如何進行的?
我們接下來看看 Servlet 的請求和響應(yīng)流程。
如圖 6 所示,這里通過 8 個步驟展示了 HTTP 請求和響應(yīng)的流程:
1.用戶通過瀏覽器發(fā)起 HTTP 請求。
2.Servlet 容器在接受到請求以后會對 HTTP 請求進行解析。
3.通過解析的結(jié)果以及配置信息創(chuàng)建 Servlet 實例。
4.實例創(chuàng)建以后調(diào)用 Servlet 實例的 init 方法完成實例初始化工作。
5.接下來就是調(diào)用 Servlet 中的 Service 方法完成具體業(yè)務(wù)。
6.Service 方法完成以后會將響應(yīng)信息返回給 Servlet 容器。
7.Servlet 容器將 Servlet 返回的信息創(chuàng)建成 HTTP 響應(yīng)返回給瀏覽器端。
8.最后容器關(guān)閉的時候,Servlet 容器調(diào)用 destroy 方法卸載掉 Servlet,并且釋放對應(yīng)的資源。
Tomcat的結(jié)構(gòu)比較復(fù)雜,但是又比較模塊化,所以只要我們找到了最核心的模塊,對于tomcat的整體架構(gòu)和工作原理就很好理解了。
Connector(連接器)組件負責(zé)生成請求對象和響應(yīng)對象的,Tomcat默認為HttpConnector,負責(zé)根據(jù)收到的Http請求報文生成Request對象和Response對象,并把這兩個對象傳遞給Container,然后根據(jù)Response中的內(nèi)容生成相應(yīng)的HTTP報文。
Container是容器的父接口,所有子容器都必須實現(xiàn)這個接口,簡單來說就是服務(wù)器部署的項目是運行在Container中的。Container里面的項目獲取到Connector傳遞過來對應(yīng)的的Request對象和Response對象進行相應(yīng)的操作。
Connector可以根據(jù)不同的的設(shè)計和應(yīng)用場景進行替換,而一個Container可以對應(yīng)多個Connector。多個Connector和一個Container就形成了一個Service,而Service可以對外提供服務(wù)。
而service由server提供生存環(huán)境并控制其生命周期,
假設(shè)有一個請求http://localhost:8080/test/index.jsp 我們梳理一下流程
1.請求先發(fā)送到本機端口8080,然后被在那里偵聽的Coyote HTTP/1.1 Connector獲得;
2. Connector把該請求交給它所在的Service的Engine來處理,并等待Engine的回應(yīng);
3.Engine獲得請求localhost:8080/test/index.jsp,匹配它所有虛擬主機Host;
4.Engine匹配到名為localhost的Host(即使匹配不到也把請求交給該Host處理,因為該Host被定義為該Engine的默認主機);
5.localhost Host獲得請求/test/index.jsp,匹配它所擁有的所有Context;
6.Host匹配到路徑為/test的Context(如果匹配不到就把該請求交給路徑名為"“的Context去處理);
7.path=”/test"的Context獲得請求/index.jsp,在它的mapping table中尋找對應(yīng)的servlet;
8.Context匹配到URL PATTERN為*.jsp的servlet,對應(yīng)于JspServlet類;
9.構(gòu)造HttpServletRequest對象和HttpServletResponse對象,作為參數(shù)調(diào)用JspServlet的doGet或doPost方法;
10.Context把執(zhí)行完了之后的HttpServletResponse對象返回給Host;
11.Host把HttpServletResponse對象返回給Engine;
12.Engine把HttpServletResponse對象返回給Connector;
13.Connector把HttpServletResponse對象返回給客戶browser;
上面我們知道了流程,但是connector是如何接受請求?又如何封裝成Request和Response對象的呢?
Connector是使用ProtocolHandler來處理請求的,不同的ProtocolHandler代表不同的連接類型,比如我們之前說到的Http11Protocol使用的是普通Socket來連接的,Http11NioProtocol使用的是NioSocket來連接的
可以看到ProtocolHandler由包含了三個部件:Endpoint、Processor、Adapter
Endpoint用來處理底層Socket的網(wǎng)絡(luò)連接,由于是處理底層的Socket網(wǎng)絡(luò)連接,因此Endpoint是用來實現(xiàn)TCP/IP協(xié)議的,
Processor用于將Endpoint接收到的Socket封裝成Request,用來實現(xiàn)HTTP協(xié)議的
Adapter用于將Request交給Container進行具體的處理,用來將請求適配到Servlet容器進行具體的處理
Endpoint的抽象實現(xiàn)類AbstractEndpoint里面定義的Acceptor和AsyncTimeout兩個內(nèi)部類和一個Handler接口。Acceptor用于監(jiān)聽請求,AsyncTimeout用于檢查異步Request的超時,Handler用于處理接收到的Socket,在內(nèi)部調(diào)用Processor進行處理。
到了這里,我們可以回答上面的問題了,但是Container是如何進行處理的以及處理完之后是如何將處理完的結(jié)果返回給Connector我們還不清楚,
Engine:引擎,用來管理多個站點,一個Service最多只能有一個Engine;
Host:代表一個站點,也可以叫虛擬主機,通過配置Host就可以添加站點;
Context:代表一個應(yīng)用程序,對應(yīng)著平時開發(fā)的一套程序,或者一個WEB-INF目錄以及下面的web.xml文件;
Wrapper:每一Wrapper封裝著一個Servlet的一個或多個實例;
Context和Host的區(qū)別是Context表示一個應(yīng)用,Tomcat中默認配置下webapps下的每一個文件夾目錄都是一個Context而整個webapps就是一個Host站點
我們訪問應(yīng)用Context的時候,
如果是Host(webapps)下的其他應(yīng)用,則可以使用http://www.test.com/docs進行訪問,
默認指定的根應(yīng)用(ROOT)是可以進行改變的
Container如何處理請求
Container處理請求是使用Pipeline-Valve管道來處理的
Pipeline-Valve是責(zé)任鏈模式,責(zé)任鏈模式是指在一個請求處理的過程中有很多處理者依次對請求進行處理,每個處理者負責(zé)做自己相應(yīng)的處理,處理完之后將處理后的請求返回,再讓下一個處理著繼續(xù)處理。
每個Pipeline都有特定的Valve,而且是在管道的最后一個執(zhí)行,這個Valve叫做BaseValve,BaseValve是不可刪除的;
在上層容器的管道的BaseValve中會調(diào)用下層容器的管道。
當執(zhí)行到StandardWrapperValve的時候,會在StandardWrapperValve中創(chuàng)建FilterChain,并調(diào)用其doFilter方法來處理請求,這個FilterChain包含著我們配置的與請求相匹配的Filter和Servlet,其doFilter方法會依次調(diào)用所有的Filter的doFilter方法和Servlet的service方法,這樣請求就得到了處理!
當所有的Pipeline-Valve都執(zhí)行完之后,并且處理完了具體的請求,這個時候就可以將返回的結(jié)果交給Connector了,Connector在通過Socket的方式將結(jié)果返回給客戶端。
如果執(zhí)行過程中間出現(xiàn)問題就拋異常。
總結(jié)
以上是生活随笔為你收集整理的Tomcat的实现原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【数据结构与算法】【算法思想】【算法应用
- 下一篇: 互联网产品跨部门沟通的10个原则(转)