不過這種“美好生活”沒有持續多久就破滅了。原因就是了解到了struts2,這東西並沒有用servlet,而是用filter實現的。我有點不相信,但是翻了很久的Struts2還是沒有發現servlet的影子。可是這東西不也是在tomcat下面運行的嗎?傳說中的servlet容器(tomcat)莫非另有乾坤?廢話到這裏爲止吧!大概講了一下一個JSP菜鳥如何開始分析tomcat源碼的。下面進入正題:
我主要的參考資料是《深入剖析tomcat》的中文版,這個pdf可以在CSDN上免費下載到。這裏我不想過多重複書中已經寫得非常詳細的內容,主要探討一下filter和servlet的關係。當然首先還是搬運一下,下圖描述了tomcat的方法調用序列。
具體過程如下:
(1)connector 創建 request 和 response 對象;
(2)connector 調用 StandardContext 實例的 invoke 方法;
(3)StandardContext 接着調用其 pipeline 的 invoke 方法,StandardContext 中 pipeline 的 basic valve 是
StandardContextValve,因此,StandardContext 的 pipeline 會調用 StandardContextValve 的 invoke 方法;
(4)StandardContextValve 的 invoke 方法獲取 wrapper 處理請求,調用 wrapper 的 invoke 方法;
(5)StandardWrapper 是 Wrapper 接口的標準實現,StandardWrapper 實例的 invoke 方法會調用其
pipeline 的 invoke 方法;
(6)StandardWrapper 的 pipeline 中的 basic valve 是 StandardWrapperValve,因此,會調用其 invoke 方
法,StandardWrapperValve 調用 wrapper 的 allocate 方法獲取 servlet 實例;
(7)allocate 方法調用 load 方法載入 servlet 類,若已經載入,則無需重複載入;
(8)load 方法調用 servlet 的 init 方法;
(9)StandardWrapperValve 調用 servlet 的 service 方法。
這個過程倒是說得很仔細,但仍然沒有看到filter的影子。不過功夫不負有心人,還是被我發現了。
// Create the filter chain for this request
ApplicationFilterChain filterChain =
createFilterChain(request, servlet);
/*略
String jspFile = wrapper.getJspFile();
if (jspFile != null)
sreq.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
else
sreq.removeAttribute(Globals.JSP_FILE_ATTR);
if ((servlet != null) && (filterChain != null)) {
filterChain.doFilter(sreq, sres);
}
sreq.removeAttribute(Globals.JSP_FILE_ATTR);
問題的答案就在上面的7,、8、9三步。在StandardWrapperValve的invoke中(也就是上面貼的代碼),我們終於看到了filter的身影。倒數第三行的代碼就是調用servlet的入口,傳說中的doFilter()。當然對於Struts2,doFilter的作用就不是最終調用servlet的service方法了,而是形成了一種代理機制。這種機制相當於攔截的作用,Struts2中的各種filter的目的就是把Http請求路由到Action上,而不是servlet上。感覺問題還是沒有解答透徹,比如對於Struts2,doFilter綁定的servlet是在哪兒初始化的?個人猜想這個servlet應該是Struts2自己弄的一個“傀儡皇帝”。後邊繼續研究研究。