tomcat源碼分析之filter和servlet

        學習JavaEE的時候,看的是尚學堂的視頻。記得老師在介紹各種web服務器的時候,說tomcat其實應該叫做servlet容器。這一句話不說不要緊,一說就讓我糾結了好幾個月。當時老師講JavaEE的時候並沒有深入的講tomcat。偶然間提到一次servlet的調用機制就覺得高貴冷豔。沒有辦法,當時知識有限,我只好以“tomcat本來就是servlet容器”自我安慰。
        不過這種“美好生活”沒有持續多久就破滅了。原因就是了解到了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自己弄的一個“傀儡皇帝”。後邊繼續研究研究。
發佈了49 篇原創文章 · 獲贊 11 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章