說過了服務器啟動,最后來看一下請求處理過程, 服務器啟動好后,處于待命狀態(tài),請求來了,請求處理過程由分兩個建階段:
-
請求連接建立過程 ( 以 NIO 為例 )
前面有提到,從線程池中固定分配了一個線程專門用于等待新連接,就是上圖的監(jiān)聽線程,沒有請求來時,該線程是阻塞在 accept () 方法上的,當新連接來建立連接時, accept 方法分配了一個 socket ,并將其設置為 nonblocking, 最后要做的就是將該 socket 丟給某個 Acceptor 線程 ( 基本上機會均等 ) 處理,然后立馬返回繼續(xù)處于接受狀態(tài),可以這個線程的工作是相當?shù)暮唵蔚模誓且彩窍喈數(shù)母摺?
Acceptor 線程有很多個 ( 全部來自于線程池,并且固定分配出來,基于 jetty.xml 配置中的 Acceptors 配置數(shù)量 ) ,每個線程都維護了一個 SelectSet, 每個 SelectSet 又對應了一個 Selector, 這些線程會檢測當前是否有任務來,例如檢測 changes 隊列中是否有任務,有并且是新連接,那么就迅速建立一個 endpoint 點負責管理這個 socket ,并注冊 read 事件,后續(xù)該 selector 就會負責該連接的 read 事件監(jiān)聽。
對于連接很多的情況,這里分很多個 Selector 來分別監(jiān)聽,提高了效率。
-
請求數(shù)據(jù)處理過程 ( 以 NIO 為例 )
當數(shù)據(jù)發(fā)送過來時, Selector 檢測到 read 事件,會立馬調(diào)用 endpoint 的 schedule() 方法,該方法目的就是從線程池分配一個 worker 線程專門來處理這個 read 事件,而自己卻立馬返回繼續(xù)監(jiān)聽,可見,這里也是一個高效的處理方式。
業(yè)務線程分配成功后,負責請求的讀取以及解析,如果請求是完整的,那么就開始調(diào)用 Server 的 handle 方法 (server 本身就是一個 handler) ,開始 handler 的處理,最后調(diào)用到 SerlvetHandler ,最終交給 Servlet 、 Filter ,開始了我們的自己應用。
后記
1、 Jetty 的模塊化做得非常好,可以隨時替換其中的絕大部分關鍵部件,也可以拆掉,例如不需要處理 Session ,可以簡單配置一下即可搞定,不需要處理 Servlet, 可以不用配置 ServletHandler.
2、 jetty 采用非阻塞 IO 時,我們可以看到從頭到尾的幾次線程池分配情況, 第一次 分配一個固定線程監(jiān)聽新連接, 第二次 分配 N 個固定線程監(jiān)聽 read 事件(這里的 N 個線程在 7.3 版本中配置文件中配置 acceptors 數(shù)量即可,也就是說會從線程池固定分配 N 個線程出來), 第三次 分配線程就是 read 事件到來之后,立即分配一個業(yè)務線程 ( 這個是臨時的,用了要回收 ) 處理數(shù)據(jù)直到我們應用返回結(jié)果。 最后有一個地方 上面都沒有說到,那就是超時等原因要關閉連接時,是分配了臨時線程來處理這些事情
3、 模塊化、切分 task
4、 小,真的很小
延伸閱讀
1、 Jetty continuations
2、 Tomcat comet
更多文章、技術交流、商務合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
