前面已經詳細介紹了 tomcat 的執行緒模型, 那麼對於乙個請求, tomcat 到底是如何處理的呢 ?
由 nioendpoint 的內部類 acceptor 監聽連線
可以看到, 呼叫了 poller 的 registry 方法, 傳了乙個 niochannel 物件進來// 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 類也實現了 runnable 介面, 檢視他的 run 方法public
void
register
(final niochannel socket)
else
// 將封裝好的 pollerevent 放入 events 佇列
addevent
(r);
}
請求來到 socketprocessor , 這仍然是 nioendpoint 的內部類, 只是獲取了以下 handler 物件, 然後交給 connectionhandler 繼續處理, 檢視它的 process 方法// 一直迴圈
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()
;
http11processor 繼續處理, http11processor 對請求頭進行處理, 並將 uri 路徑攜帶的資料放入 inputbuffer 中, 並將資料封裝在public socketstate process
if(processor == null)..
.// 放入快取, 關聯這個 processor 和 連線
connections.
put(socket, processor)
; socketstate state = socketstate.closed;
do
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;..
..}
執行完所有 filter 的 dofilter 方法後, 最後呼叫了 servlet 的 service 方法, 到了這裡, servlet 終於開始幹活了, 一次完整的請求結束, 至於 tomcat 是如何響應的, 也就是重定向和請求**, 還有熱部署是如何實現的, 下篇繼續public
final
void
invoke
(request request, response response)
throws ioexception, servletexception }.
...// 建立 filter 鏈
createfilterchain
;try
else
}finally}}
....
}
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...