Tomcat請求處理流程與源碼淺析(最新推薦)
Tomcat請求處理流程與源碼淺析
一丶Connector
在tomcat中,Connector負(fù)責(zé)開啟socket并且監(jiān)聽客戶端請求,返回響應(yīng)數(shù)據(jù)。
其中:
- Endpoint:tomcat中沒有這個(gè)接口,只有AbstractEndpoint,它負(fù)責(zé)啟動(dòng)線程來監(jiān)聽服務(wù)器端口,并且在接受到數(shù)據(jù)后交給Processor處理
- Processor:Processor讀取到客戶端請求后按照請求地址映射到具體的容器進(jìn)行處理,這個(gè)過程請求映射,Processor實(shí)現(xiàn)請求映射依賴于Mapper對象,在容器發(fā)生注冊和注銷的時(shí)候,MapperListener會監(jiān)聽到對應(yīng)的事件,從而來變更Mapper中維護(hù)的請求映射信息。
- ProtocolHandler:協(xié)議處理器,針對不同的IO方式(NIO,BIO等)和不同的協(xié)議(Http,AJP)具備不同的實(shí)現(xiàn),ProtocolHandler包含一個(gè)Endpoint來開啟端口監(jiān)聽,并且包含一個(gè)Processor用于按照協(xié)議讀取數(shù)據(jù)并將請求交給容器處理。
- Acceptor:Acceptor實(shí)現(xiàn)了Runnable接口,可以作為一個(gè)線程啟動(dòng),使用Socket API監(jiān)聽指定端口,用于接收用戶請求。
- Poller:主要用于監(jiān)測注冊在原始 scoket 上的事件是否發(fā)生,Acceptor接受到請求后,會注冊到Poller的隊(duì)列中。
二丶NioEndpoint 初始化ServerSocketChannel
springboot內(nèi)嵌tomcat,一般默認(rèn)使用NioEndpoint,在NioEndpoint#start方法中,會觸發(fā)NioEndpoint#bind
三丶NioEndpoint 啟動(dòng)Poller和Acceptor線程
NioEndpoint#start方法最后會觸發(fā)Poller線程和Acceptor線程的啟動(dòng)
可以看到NioEndpoint內(nèi)部的Poller,和Acceptor都是單獨(dú)使用一個(gè)守護(hù)線程來運(yùn)行。
四丶Acceptor接收請求
1.endpoint.countUpOrAwaitConnection()限制連接數(shù)
其內(nèi)部使用LimitLatch#countUpOrAwait方法限制連接數(shù),如果連接數(shù)達(dá)到了上限,那將掛起當(dāng)前線程,也就是掛起Acceptor線程,從而導(dǎo)致無法有更多的請求連接上來,最大連接數(shù)默認(rèn)為8*1024。
LimitLatch 內(nèi)部持有一個(gè)AbstractQueuedSynchronizer,限制連接數(shù)將調(diào)用其acquireSharedInterruptibly(1),然后會調(diào)用到AQS的tryAcquireShared,其內(nèi)部使用AtomicLong來進(jìn)行連接的計(jì)數(shù)。
2.NioEndpoint#serverSocketAccept 接收Socket連接
由于NioEndpoint前面調(diào)用了ServerSocketChannel#configureBlocking(true),所以serverSock#accept,在沒有連接上來時(shí),不會立馬返回null,而是阻塞直到連接來到。
3.NioEndpoint#setSocketOptions將SocketChannel注冊到Poller
在Acceptor線程接收到SocketChannel后,會調(diào)用Poller#register方法進(jìn)行注冊,Acceptor只負(fù)責(zé)接受請求,請求后續(xù)的處理由Poller線程負(fù)責(zé)
最終請求被包裝為PollerEvent丟到Poller的事件隊(duì)列SynchronizedQueue中,SynchronizedQueue使用synchronized保證線程安全。
wakeupCounter 是AtomicLong類型,Acceptor接受到請求,將請求封裝為PollerEvent后會調(diào)用wakeupCounter#incrementAndGet方法,進(jìn)行+1操作
Poller在使用Selector,進(jìn)行IO多路復(fù)用的時(shí)候,會進(jìn)行如下操作
可以看到,如果wakeupCounter大于0,Poller會調(diào)用 selector.selectNow()
(非阻塞立馬返回),反之調(diào)用selector.select(selectorTimeout)
(超時(shí)并阻塞)。
也就說Acceptor接受到請求越多,wakeupCounter越大,越會讓Poller調(diào)用selector.selectNow()減少阻塞,從而讓Poller更快的檢查事件是否就緒,從而讓請求更及時(shí)的被處理。
五丶Poller處理事件
1.events方法查看事件隊(duì)列是否具備事件
上面我們說到Acceptor在建立連接后,將SocketChannel包裝成NioSocketWrapper塞到了Poller的事件隊(duì)列中。而Poller線程則會一直輪詢這個(gè)隊(duì)列進(jìn)行事件的獲取
2.Poller 使用Selector進(jìn)行select
通過Selector獲取獲取當(dāng)前就緒的IO,keyCount記錄就緒數(shù)目。
3.Poller 處理就緒IO
processKey會調(diào)用到processSocket,最終使用tomcat線程池中的線程進(jìn)行異步處理
最終會找到Processor進(jìn)行處理(默認(rèn)使用緩存的,避免重復(fù)new對象,頻繁gc,如果緩存沒有那么使用ProtocolHandler 創(chuàng)建出一個(gè)),這里的Processor就是Http11Processor
然后根據(jù)事件類型進(jìn)行不同的處理,如果是讀事件那么會調(diào)用Http11Processor#service進(jìn)行處理,然后會繼續(xù)交給CoyoteAdapter調(diào)用其service進(jìn)行處理。
六丶CoyoteAdapter處理請求
1.使用Mapper找到請求對應(yīng)的Host,Context,Wrapper
下圖是的模型,如果使用了SpringMVC,這里的Wrapper會存在DispatchServlet
如下是Mapper找到的MappingData
2.Pipeline執(zhí)行
上面說到,Mapper會找到當(dāng)前請求所屬的host,context和對應(yīng)的Wrapper,緊接著會進(jìn)行Pipeline的執(zhí)行。
為了增強(qiáng)擴(kuò)展性,tomcat定義了Pipeline(管道)和Valve(閥),Pipeline使用職責(zé)鏈的方式串聯(lián)多個(gè)Valve——來自客戶端的請求如同流水一樣流淌在管道中,受到每一個(gè)閥的作用。
Pipeline中維護(hù)了基礎(chǔ)的Valve,始終位于Pipeline末端,通過Pipeline#addValve添加的Valve違約基礎(chǔ)的Valve之前。
在Tomcat中Engine,Host,Context,Wrapper都有對應(yīng)的Valve實(shí)現(xiàn),同時(shí)維護(hù)了一個(gè)Pipeline,從而讓我們可以對請求的處理進(jìn)行擴(kuò)展。
下面是比較重要的Valve
StandardEngineValve :Engine對應(yīng)的Valve,負(fù)責(zé)請求是否通過mapper找到了對應(yīng)的Host,并觸發(fā)Host對應(yīng)的Valve
ErrorReportValve: 錯(cuò)誤報(bào)告Valve讓后續(xù)的Valve繼續(xù)執(zhí)行,如果執(zhí)行出現(xiàn)錯(cuò)誤那么會刷新響應(yīng)流,讓客戶端收到響應(yīng)
StandardHostValve:Host對應(yīng)的Valve,如果請求沒有匹配的context返回404,反之調(diào)用Context對應(yīng)的Valve
StandardContextValve:Context對應(yīng)的Valve,如果請求路徑以/META-INF/,或者/WEB-INF/開頭,會直接返回404,反之繼續(xù)調(diào)用Wrapper對應(yīng)的
StandardWrapperValve:Wrapper對應(yīng)的Valve,會負(fù)責(zé)組裝Servlet和Filter,并執(zhí)行FilterChain#doFilter方法
Filter的匹配主要通過DispatchType和Filter設(shè)置的路徑,
在SpringBoot項(xiàng)目中可以使用FilterRegistrationBean#setDispatcherTypes,和addUrlPatterns進(jìn)行指定。
3.FilterChain執(zhí)行
在Tomcat中ApplicationFilterChain實(shí)現(xiàn)了Java Servlet規(guī)范中的FilterChain。
其中使用ApplicationFilterConfig是對FilterConfig的實(shí)現(xiàn),內(nèi)部持有一個(gè)Filter。
ApplicationFilterChain包含多個(gè)ApplicationFilterConfig,使用數(shù)組和pos屬性記錄當(dāng)前執(zhí)行到第幾個(gè)Filter
Filter都執(zhí)行結(jié)束后,將執(zhí)行Servlet#service方法
在SpringMVC項(xiàng)目中,會調(diào)用到DispatcherServlet#service,最終調(diào)用到Controller。
到此這篇關(guān)于Tomcat請求處理流程與源碼淺析的文章就介紹到這了,更多相關(guān)Tomcat請求處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在IDEA 2020.3.1中部署Tomcat并且創(chuàng)建第一個(gè)web項(xiàng)目的過程詳解
這篇文章主要介紹了在IDEA 2020.3.1中部署Tomcat并且創(chuàng)建第一個(gè)web項(xiàng)目,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02tomcat相關(guān)配置與eclipse集成_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了tomcat相關(guān)配置與eclipse集成_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理的相關(guān)資料,需要的朋友可以參考下2017-07-07Tomcat服務(wù)器配置https認(rèn)證(使用keytool生成證書)
本文主要介紹了Tomcat服務(wù)器配置https認(rèn)證,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07