Tomcat底层原理
一、Tomcat啟動時(shí)到底對我們的應(yīng)用程序做了什么?
當(dāng)我們把一個(gè)應(yīng)用程序的war包放到Tomcat的webapps目錄后,啟動Tomcat,然后就可以通過瀏覽器發(fā)送Http請求訪問該war包內(nèi)的Servlet了。
這個(gè)過程包括:
1、啟動Tomcat
2、Tomcat處理Http請求
而啟動Tomcat的目的就是為了處理Http請求。
一個(gè)Http請求通常是這樣子的:
http://localhost:8080/app/helloServlet
這個(gè)請求包括:
我們通俗點(diǎn)來理解這個(gè)Http請求就是:瀏覽器通過Http協(xié)議,請求localhost:8080上的myapp應(yīng)用內(nèi)的helloServlet。
Tomcat架構(gòu)俯視圖:
二、那分析這個(gè)Http請求有什么用呢?和Tomcat有什么關(guān)系?
當(dāng)然有關(guān)系,上面這個(gè)Http請求中的localhost:8080其實(shí)代表的就是Tomcat。我們一個(gè)應(yīng)用程序想要從外部接收網(wǎng)絡(luò)數(shù)據(jù),那就要綁定一個(gè)端口,這個(gè)跟TCP協(xié)議有關(guān)系,外部請求發(fā)送給該端口,就能被對于的程序所接收到。Tomcat也是這樣,所以,Tomcat默認(rèn)綁定的就是8080。
所以上面這個(gè)Http請求首先是被Tomcat接收到,然后去解析這個(gè)請求。
解析這個(gè)請求包括:
當(dāng)Tomcat把從8080端口獲取的請求解析完成后,它就應(yīng)該根據(jù)應(yīng)用名和Servlet名字去找Servlet實(shí)現(xiàn)類了,只有找到Servlet實(shí)現(xiàn)類才能真正執(zhí)行Servlet里面的doGet或doPost方法。
所以,這里又分兩步:
根據(jù)請求中的應(yīng)用名和Servlet名怎么找到對應(yīng)的Servlet實(shí)現(xiàn)類呢 怎么執(zhí)行Servlet實(shí)現(xiàn)類中跟請求對應(yīng)的方法呢首先關(guān)于第二點(diǎn),很簡單:可以用***反射***
那么對于第一點(diǎn)該怎么實(shí)現(xiàn)呢?
其實(shí)也很簡單,要么默認(rèn),要么映射。
默認(rèn)的意思就是,請求中的Servlet名就是類名,這種可行,但是不好用,一個(gè)類還有包名的,萬一在一個(gè)應(yīng)用中,存在不同的包下存在名字相同的Servlet,這個(gè)時(shí)候就尷尬了。
所以最好的方式就是映射,一個(gè)Servlet名對應(yīng)一個(gè)Servlet實(shí)現(xiàn)類。這也就是為什么我們在定義Servlet時(shí),一定要做一個(gè)mapping關(guān)系,不管是通過@WebServlet注解還是在web.xml中,都需要配置一個(gè)mapping才能被訪問到。
所以,Tomcat通過監(jiān)聽端口,獲取數(shù)據(jù),然后解析數(shù)據(jù),根據(jù)請求url找到對應(yīng)的Servlet實(shí)現(xiàn)類,然后通過反射執(zhí)行Servlet實(shí)現(xiàn)類中的方法。
這個(gè)流程并不難,如果我們自己實(shí)現(xiàn),30分鐘內(nèi)可能就能實(shí)現(xiàn)出來這么一個(gè)功能,這也是Tomcat的主線功能,那么Tomcat復(fù)雜在哪呢?
其實(shí)還是復(fù)雜在這條主線,這條主線再拆分一下就是兩步:
tomcat容器對比:
三、Servlet
我們在來細(xì)想一下這里的第二步:尋找并執(zhí)行Servlet
我們通常說Tomcat是一個(gè)Servlet容器,到底體現(xiàn)在哪,怎么體現(xiàn)的呢?
我們得先來理解一下Servlet,Servlet=Server+Applet,表達(dá)的意思就是運(yùn)行在服務(wù)端的應(yīng)用程序,它跟運(yùn)行在客戶端的應(yīng)用程序是相對的,運(yùn)行在客戶端的應(yīng)用程序,可以隨著用戶的操作而發(fā)生變化,而運(yùn)行在服務(wù)端的應(yīng)用程序,用戶是不能直接操作的,你只能通過發(fā)送網(wǎng)絡(luò)請求來操作它,這就是Servlet的由來。這也就是為什么Servlet規(guī)范里會定義ServletRequest,ServletResponse接口,都是跟請求相關(guān)的,所以,Servlet其實(shí)就為Java程序員方便處理請求和響應(yīng)的一種抽象,作為Java程序員,你只需要通過定義Servlet,然后接收到的ServletRequest對象就代表請求,而不用關(guān)心ServletRequest具體的實(shí)現(xiàn)類是什么,是誰實(shí)現(xiàn)的,都不用關(guān)系,只要知道這個(gè)對象代表一個(gè)請求即可。
所以誰來實(shí)現(xiàn)這些接口呢?大家自然就能想到了,是Tomcat、Jetty這些了。比如Tomcat中對應(yīng)的請求實(shí)現(xiàn)類是RequestFacade,我們在Servlet中進(jìn)行強(qiáng)制轉(zhuǎn)化是沒有問題的,比如這么寫:
我們重新理解了Servlet之后,就可以再來理解Tomcat了,Tomcat確實(shí)是一個(gè)容器,但是是一個(gè)分層的容器。因?yàn)橐粋€(gè)Servlet代表一個(gè)功能,一個(gè)應(yīng)用中可以有多個(gè)Servlet,所以在Tomcat中存在Context容器,Context容器中收納Servlet,Context就代表應(yīng)用,也就是應(yīng)用上下文,然后我們的應(yīng)用是部署在主機(jī)上的,所以Tomcat中存在Host容器,一個(gè)Host容器中可以容納多個(gè)Context容器,再繼續(xù),我們可能是多個(gè)主機(jī)所提供的功能屬于同一范疇的,所以在Tomcat中,在Host之上還有一層Engine。所以我們說的容器包括:Engine、Host、Context。
而Tomcat除開實(shí)現(xiàn)了這個(gè)層級結(jié)構(gòu)之外,還提供了一些輔助功能。
既然現(xiàn)在容器分層了,所以一個(gè)請求在尋找Servlet的過程中,就會經(jīng)過每一層容器,那么每層容器在這個(gè)過程中都可以去做一些事情,并且允許用戶自定義這些事情,比如可以在Host層去指定:所有請求該Host的請求都將日志打印到hostname.log文件中,或者所有請求該Host的請求都由該Host添加一下參數(shù),其他容器也類似,這其實(shí)就是一種責(zé)任鏈模式,Tomcat中實(shí)現(xiàn)了這種模式,是通過:Pipeline和Valve實(shí)現(xiàn)的。
好,這是關(guān)于容器的分析。
接下來我們再來分析一下Tomcat是怎么解析請求的,上文我們分析了,Tomcat實(shí)際上就是把接收到的請求轉(zhuǎn)化成RequestFacade對象,最后把這個(gè)對象傳遞給Servlet。
那么Tomcat的數(shù)據(jù)從哪來的呢?上文中我們一直默認(rèn)Tomcat接收的是Http請求,那么這個(gè)Http請求是怎么到達(dá)Tomcat的呢?總不是憑空飛過來了的吧。
大家應(yīng)該想到了,是通過網(wǎng)線傳過來的,所以我們要分析Tomcat是怎么接收到Http請求,就要分析網(wǎng)絡(luò)傳輸協(xié)議了。
首先,我們?yōu)槭裁葱枰W(wǎng)絡(luò)傳輸協(xié)議呢?
網(wǎng)絡(luò)是用來傳輸數(shù)據(jù)的,比如現(xiàn)在主機(jī)A有一份數(shù)據(jù)要發(fā)送給主機(jī)B,那么主機(jī)A在擁有數(shù)據(jù)的同時(shí)還是要知道主機(jī)B的地址,也就是IP,所以現(xiàn)在相當(dāng)于主機(jī)A上要有:數(shù)據(jù)+對方IP地址
四、流程圖
Tomcat:
(1)Tomcat中只有一個(gè)Server,一個(gè)Server可以有多個(gè)Service,一個(gè)Service可以有多個(gè)Connector和一個(gè)Container;
(2) Server掌管著整個(gè)Tomcat的生死大權(quán);
(4)Service 是對外提供服務(wù)的;
(5)Connector用于接受請求并將請求封裝成Request和Response來具體處理;
(6)Container用于封裝和管理Servlet,以及具體處理request請求;
Connector:
四個(gè)子容器:
(1)Engine:引擎,用來管理多個(gè)站點(diǎn),一個(gè)Service最多只能有一個(gè)Engine;
(2)Host:代表一個(gè)站點(diǎn),也可以叫虛擬主機(jī),通過配置Host就可以添加站點(diǎn);
(3)Context:代表一個(gè)應(yīng)用程序,對應(yīng)著平時(shí)開發(fā)的一套程序,或者一個(gè)WEB-INF目錄以及下面的web.xml文件;
(4)Wrapper:每一Wrapper封裝著一個(gè)Servlet;
上述的包含關(guān)系或者說是父子關(guān)系,都可以在tomcat的conf目錄下的server.xml配置文件中看出,下圖是刪除了注釋內(nèi)容之后的一個(gè)完整的server.xml配置文件(Tomcat版本為8.0)
更多詳情
五、那么Tcp是用來干什么的呢?
回到上面的場景,主機(jī)A想把數(shù)據(jù)發(fā)送給主機(jī)B,那誰來保證數(shù)據(jù)能可靠的到達(dá)對方呢?這就是Tcp協(xié)議所要做的事情。
那Http協(xié)議又是怎么回事呢?我們上面接收的Ip,Tcp都是跟傳輸相關(guān)的,而Http是跟應(yīng)用相關(guān)的,是跟數(shù)據(jù)所表達(dá)的意義相關(guān)的,比如,主機(jī)A發(fā)一份數(shù)據(jù)給主機(jī)B之后,主機(jī)B接收到這份數(shù)據(jù)后,它要干什么呢?它要執(zhí)行什么動作呢?這就是Http協(xié)議所要表達(dá)的,通過在數(shù)據(jù)中增加一些有意義的元素,比如請求方法,這樣數(shù)據(jù)接收方能更快的根據(jù)Http協(xié)議解析數(shù)據(jù),完成對應(yīng)的動作。
解析的比較粗,因?yàn)檫@不是本文的重點(diǎn),我的重點(diǎn)是,那么誰來實(shí)現(xiàn)Http協(xié)議,誰來實(shí)現(xiàn)Tcp協(xié)議呢?
答案是:操作系統(tǒng)來實(shí)現(xiàn)Tcp協(xié)議,比如Linux、Windows,運(yùn)行在操作系統(tǒng)之上的其他應(yīng)用程序來實(shí)現(xiàn)Http協(xié)議,比如瀏覽器、Tomcat。
比如Linux的源碼中就有關(guān)于Tcp協(xié)議的實(shí)現(xiàn),包括三次握手,四次揮手,都是通過c語言來實(shí)現(xiàn)的。那么瀏覽器它依照Http協(xié)議定義好數(shù)據(jù)之后,怎么利用Tcp協(xié)議發(fā)送出去呢?Tomcat怎么利用Tcp協(xié)議接收數(shù)據(jù)呢?
瀏覽器能不能直接調(diào)用操作系統(tǒng)中實(shí)現(xiàn)TCP協(xié)議關(guān)于發(fā)送數(shù)據(jù)的函數(shù)呢?Tomcat能不能調(diào)用對應(yīng)接收數(shù)據(jù)的函數(shù)呢?
原理上是可以的,但是就像我們開發(fā)業(yè)務(wù)一樣,我們不會將真正實(shí)現(xiàn)業(yè)務(wù)的方法直接暴露給其他人調(diào)用,而會提供一個(gè)接口,操作系統(tǒng)也一樣,這個(gè)接口就是Socket。
所以Tomcat是通過Socket從操作系統(tǒng)獲取數(shù)據(jù)的,拿到數(shù)據(jù)后進(jìn)行解析。
而Tomcat從操作系統(tǒng)系統(tǒng)拿數(shù)據(jù)又有幾種方式,也就是IO模型:BIO,NIO,AIO,這些不同的模式Tomcat都是支持的,只需要在server.xml中進(jìn)行配置即可。
簡單記錄了一下關(guān)于Tomcat的隨筆,其實(shí)關(guān)于TSocket、IO模型可以寫得更多一點(diǎn),限于篇幅,本篇就到此為止吧,下次繼續(xù)。
總結(jié)
以上是生活随笔為你收集整理的Tomcat底层原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 每天一个linux命令(9):nl命令
- 下一篇: g4600黑苹果efi_Hackinto