六 Tomcat 原始碼系列之 請求處理

2021-10-08 08:43:52 字數 4896 閱讀 5008

前面已經詳細介紹了 tomcat 的執行緒模型, 那麼對於乙個請求, tomcat 到底是如何處理的呢 ?

由 nioendpoint 的內部類 acceptor 監聽連線

// acceptor 實現類 runable 介面, 直接檢視 run 方法

int errordelay =0;

// 一直迴圈, 直到收到 "shutdown" 命令

while

(running)

catch

(interruptedexception e)}if

(!running)

state = acceptorstate.running;

try...

.// configure the socket

if(running &&

!paused)}.

...}

----

----

----

----

----

----

// 檢視 setsocketoptions 方法

protected

boolean

setsocketoptions

(socketchannel socket)

tryelse

}else

// 使用輪轉法, 選擇乙個 poller 物件

// 繼續封裝, niochannel 封裝成為 pollerevent 物件

getpoller0()

.register

(channel)

;}

可以看到, 呼叫了 poller 的 registry 方法, 傳了乙個 niochannel 物件進來

public

void

register

(final niochannel socket)

else

// 將封裝好的 pollerevent 放入 events 佇列

addevent

(r);

}

poller 類也實現了 runnable 介面, 檢視他的 run 方法

//  一直迴圈

while

(true

)else

wakeupcounter.

set(0)

;}..

..//either we timed out or we woke up, process events first

if(keycount ==0)

hasevents =

(hasevents |

events()

);// 遍歷所有 (存在事件的) selectionkey

iterator

iterator =

keycount >

0? selector.

selectedkeys()

.iterator()

: null;

while

(iterator != null && iterator.

hasnext()

)else

}// 超時退出

timeout

(keycount, hasevents);}

getstoplatch()

.countdown()

;

請求來到 socketprocessor , 這仍然是 nioendpoint 的內部類, 只是獲取了以下 handler 物件, 然後交給 connectionhandler 繼續處理, 檢視它的 process 方法

public socketstate process

if(processor == null)..

.// 放入快取, 關聯這個 processor 和 連線

connections.

put(socket, processor)

; socketstate state = socketstate.closed;

do

http11processor 繼續處理, http11processor 對請求頭進行處理, 並將 uri 路徑攜帶的資料放入 inputbuffer 中, 並將資料封裝在org.apache.coyote.request, 和org.apache.coyote.response物件中, 然後將這個兩個物件傳給 coyoteadapter 進一步處理

其實這就是乙個介面卡, 將org.apache.coyote.request轉換為org.apache.catalina.connector.request, 將org.apache.coyote.response轉換為org.apache.catalina.connector.response(介面卡模式), 檢視它的 service 方法

public

void

service

(org.apache.coyote.request req, org.apache.coyote.response res)

throws exception

if(connector.

getxpoweredby()

)boolean async =

false

;boolean postparsesuccess =

false

; req.

getrequestprocessor()

.setworkerthreadname

(thread_name.

get())

;try..

..}

protected

boolean

postparserequest

(org.apache.coyote.request req, request request,

org.apache.coyote.response res, response response)

throws ioexception, servletexception

else

// **

string proxyname = connector.

getproxyname()

;int proxyport = connector.

getproxyport()

;if(proxyport !=0)

else

if(req.

getserverport()

==-1)

else}if

(proxyname != null)

// 未解碼的 uri

messagebytes undecodeduri = req.

requesturi()

;// uri 萬用字元匹配

if(undecodeduri.

equals

("*"))

// 已解碼的 uri , 應該為 null

messagebytes decodeduri = req.

decodeduri()

;// 下面就是解碼 uri

if(undecodeduri.

gettype()

== messagebytes.t_bytes)

// 找到 context 對應的版本 contextversion

string version = null;

context versioncontext = null;

boolean maprequired =

true;.

..while

(maprequired)

}// 在 cookie 和 ssl 會話中查詢 session id

trycatch

(illegalargumentexception e)

return

true;}

parsesessionsslid

(request)

; sessionid = request.

getrequestedsessionid()

; maprequired =

false

;// 如果沒有指定 context 版本

if(version != null && request.

getcontext()

== versioncontext)

else}.

..}// 有可能重定向

messagebytes redirectpathmb = request.()

.redirectpath;..

..}

public

final

void

invoke

(request request, response response)

throws ioexception, servletexception }.

...// 建立 filter 鏈

createfilterchain

;try

else

}finally}}

....

}

執行完所有 filter 的 dofilter 方法後, 最後呼叫了 servlet 的 service 方法, 到了這裡, servlet 終於開始幹活了, 一次完整的請求結束, 至於 tomcat 是如何響應的, 也就是重定向和請求**, 還有熱部署是如何實現的, 下篇繼續

Tomcat原始碼閱讀系列

再過十來天,就要不再是大三,而步入大四的殿堂了,求職面試的事會接踵而至,鑑於春招時的教訓,自己的學習比較缺乏系統性地整理,向他人交流自己所掌握的技術能力仍有待提高,為此將自己閱讀tomcat原始碼的過程記錄一下,並分享到部落格中,讓有同樣興趣的同學一起交流討論。注 如沒有特別說明的地方,tomcat...

Tomcat原始碼 容器啟動六 3

我們來了解一下部暑war檔案 deploy wars,and loop if additional descriptors are found deploy war files.if files null return for int i 0 i files.length i param conte...

java系列之 請求入參驗證

一 導包 hibernate validator 4.2.0.final.jar validation api 1.0.0.ga.jar 二 配置檔案 三 controller層 注意 bindingresult必須跟在實體類ambcomboform 後面 public result getcomb...