servlet/filter/listener/interceptor區別與聯絡

長風破浪發表於2016-05-26

轉自:http://www.cnblogs.com/doit8791/p/4209442.html

 servlet、filter、listener是配置到web.xml中(web.xml 的載入順序是:context-param -> listener -> filter -> servlet ),interceptor不配置到web.xml中,struts的攔截器配置到struts.xml中。spring的攔截器配置到spring.xml中。 

一、概念:

1、servlet簡介

      servlet是一種執行伺服器端的java應用程式,具有獨立於平臺和協議的特性,並且可以動態的生成web頁面,它工作在客戶端請求與伺服器響應的中間層。最早支援 Servlet 技術的是 JavaSoft 的 Java Web Server。此後,一些其它的基於 Java 的 Web Server 開始支援標準的 Servlet API。Servlet 的主要功能在於互動式地瀏覽和修改資料,生成動態 Web 內容。這個過程為:

1) 客戶端傳送請求至伺服器端;

2) 伺服器將請求資訊傳送至 Servlet;

3) Servlet 生成響應內容並將其傳給伺服器。響應內容動態生成,通常取決於客戶端的請求;

4) 伺服器將響應返回給客戶端。

在 Web 應用程式中,一個 Servlet 在一個時刻可能被多個使用者同時訪問。這時 Web 容器將為每個使用者建立一個執行緒來執行 Servlet。如果 Servlet 不涉及共享資源的問題,不必關心多執行緒問題。但如果 Servlet 需要共享資源,需要保證 Servlet 是執行緒安全的。

最新版本3.1,為了簡化開發流程,Servlet 3.0 引入了註解(annotation),這使得 web 部署描述符 web.xml 不再是必須的選擇。

 2、filter簡介

         filter是一個可以複用的程式碼片段,可以用來轉換HTTP請求、響應和頭資訊。Filter不像Servlet,它不能產生一個請求或者響應,它只是修改對某一資源的請求,或者修改從某一的響應。Servlet中的過濾器Filter是實現了javax.servlet.Filter介面的伺服器端程式,主要的用途是過濾字元編碼、做一些業務邏輯判斷等。其工作原理是,只要你在web.xml檔案配置好要攔截的客戶端請求,它都會幫你攔截到請求,此時你就可以對請求或響應(Request、Response)統一設定編碼,簡化操作;同時還可進行邏輯判斷,如使用者是否已經登陸、有沒有許可權訪問該頁面等等工作。它是隨你的web應用啟動而啟動的,只初始化一次,以後就可以攔截相關請求,只有當你的web應用停止或重新部署的時候才銷燬。Filter可認為是Servlet的一種“變種”,它主要用於對使用者請求進行預處理,也可以對HttpServletResponse進行後處理,是個典型的處理鏈。它與Servlet的區別在於:它不能直接向使用者生成響應。完整的流程是:Filter對使用者請求進行預處理,接著將請求交給Servlet進行處理並生成響應,最後Filter再對伺服器響應進行後處理。

1)        Filter有如下幾個用處。

   a)在HttpServletRequest到達Servlet之前,攔截客戶的HttpServletRequest。

根據需要檢查HttpServletRequest,也可以修改HttpServletRequest頭和資料。

   b)在HttpServletResponse到達客戶端之前,攔截HttpServletResponse。

根據需要檢查HttpServletResponse,也可以修改HttpServletResponse頭和資料。2)  Filter有如下幾個種類。

  使用者授權的Filter:Filter負責檢查使用者請求,根據請求過濾使用者非法請求。

  日誌Filter:詳細記錄某些特殊的使用者請求。

  負責解碼的Filter:包括對非標準編碼的請求解碼。能改變XML內容的XSLT Filter等。

3)  Filter可負責攔截多個請求或響應;一個請求或響應也可被多個請求攔截。

建立一個Filter只需兩個步驟:

建Filter處理類;

web.xml檔案中配置Filter。

下面先介紹一個簡單的記錄日誌的Filter,這個Filter負責攔截所有的使用者請求,並將請求的資訊記錄在日誌中。

   

 1 import java.io.IOException;
 2 import javax.servlet.*;
 3 import javax.servlet.http.HttpServletRequest;
 4 
 5 
 6 public class LogFilter implements javax.servlet.Filter {
 7     // FilterConfig可用於訪問Filter的配置資訊
 8     private FilterConfig config;
 9 
10     // 實現初始化方法
11     public void init(FilterConfig config) {
12         this.config = config;
13     }
14 
15     // 實現銷燬方法
16     public void destroy() {
17         this.config = null;
18     }
19 
20     // 執行過濾的核心方法
21     public void doFilter(ServletRequest request, ServletResponse response,
22             FilterChain chain) throws IOException, ServletException {
23         // ---------下面程式碼用於對使用者請求執行預處理---------
24         // 獲取ServletContext物件,用於記錄日誌
25         ServletContext context = this.config.getServletContext();
26         long before = System.currentTimeMillis();
27         System.out.println("開始過濾...");
28         // 將請求轉換成HttpServletRequest請求
29         HttpServletRequest hrequest = (HttpServletRequest) request;
30         // 記錄日誌
31         context.log("Filter已經截獲到使用者的請求地址: " + hrequest.getServletPath());
32         // Filter只是鏈式處理,請求依然放行到目的地址
33         chain.doFilter(request, response);
34         // ---------下面程式碼用於對伺服器響應執行後處理---------
35         long after = System.currentTimeMillis();
36         // 記錄日誌
37         context.log("過濾結束");
38         // 再次記錄日誌
39         context.log("請求被定位到" + hrequest.getRequestURI() + "所花的時間為: "
40                 + (after - before));
41     }
42 }

 

上面程式實現了doFilter()方法,實現該方法就可實現對使用者請求進行預處理,也可實現對伺服器響應進行後處理——它們的分界線為是否呼叫了chain.doFilter(),執行該方法之前,即對使用者請求進行預處理;執行該方法之後,即對伺服器響應進行後處理。

在上面的請求Filter中,僅在日誌中記錄請求的URL,對所有的請求都執行chain.doFilter (request,reponse)方法,當Filter對請求過濾後,依然將請求傳送到目的地址。如果需要檢查許可權,可以在Filter中根據使用者請求的HttpSession,判斷使用者許可權是否足夠。如果許可權不夠,直接呼叫重定向即可,無須呼叫chain.doFilter(request,reponse)方法。

   在web.xml檔案中我們需要對其需要攔截的請求配置監聽範圍,或者說過濾哪些url。

   

    <filter>
       <filter-name>logfilter</filter-name>
       <filter-class>com.mine.test.LogFilter</filter-class>
    </filter>
    <filter-mapping>
      <filter-name>logfilter</filter-name>
      <url-pattern>/*</url-pattern> <!--配置過濾的範圍   字尾符合即過濾  此處為全部過濾-->
    </filter-mapping>

 

在web.xml檔案中配置該Filter,使用init-param元素為該Filter配置引數,init-param可接受如下兩個子元素:

param-name:指定引數名。

param-value:指定引數值。

其實struts2本身就依託於一個總過濾器:

 多個匹配的Filter,是按照其在web.xml中配置的順序來執行的。 

所以這也就是,把自己的Filter或者其他的Filter(比如UrlRewrite的Filter)放在Struts的DispatcherFilter的前面的原因。因為,它們需要在請求被Struts2框架處理之前,做一些前置的工作。 
當Filter被呼叫,並且進入了Struts2的DispatcherFilter中後,Struts2會按照在Action中配置的Interceptor Stack中的Interceptor的順序,來呼叫Interceptor。 

3、listener簡介

listener監聽器,從字面上可以看出listener主要用來監聽只用。通過listener可以監聽web伺服器中某一個執行動作,並根據其要求作出相應的響應。通俗的語言說就是在application,session,request三個物件建立消亡或者往其中新增修改刪除屬性時自動執行程式碼的功能元件。比如spring 的總監聽器 會在伺服器啟動的時候例項化我們配置的bean物件 、 hibernate 的 session 的監聽器會監聽session的活動和生命週期,負責建立,關閉session等活動。

Servlet的監聽器Listener,它是實現了javax.servlet.ServletContextListener 介面的伺服器端程式,它也是隨web應用的啟動而啟動,只初始化一次,隨web應用的停止而銷燬。主要作用是: 做一些初始化的內容新增工作、設定一些基本的內容、比如一些引數或者是一些固定的物件等等。

 4、interceptor簡介

是在面向切面程式設計的,就是在你的service或者一個方法,前呼叫一個方法,或者在方法後呼叫一個方法,是基於JAVA的反射機制。比如動態代理就是攔截器的簡單實現,在你呼叫方法前列印出字串(或者做其它業務邏輯的操作),也可以在你呼叫方法後列印出字串,甚至在你丟擲異常的時候做業務邏輯的操作。

    servlet、filter、listener是配置到web.xml中(web.xml 的載入順序是:context-param -> listener -> filter -> servlet ),interceptor不配置到web.xml中,struts的攔截器配置到struts.xml中。spring的攔截器配置到spring.xml中。 

 二、生命週期:

        1、servlet:一般繼承HttpServlet(一般的,通用Servlet由javax.servlet.GenericServlet實現Servlet介面。程式設計人員可以通過使用或繼承這個類來實現通用Servlet應用。javax.servlet.http.HttpServlet實現了專門用於響應HTTP請求的Servlet,提供了響應對應HTTP標準請求的doGet()、doPost()等方法),web.xml配置servlet時如果加上load-on-start(在servlet的配置當中,<load-onstartup>1</load-on-startup>的含義是:標記容器是否在啟動的時候就載入這個servlet。當值為0或者大於0時,表示容器在應用啟動時就載入這個servlet;當是一個負數時或者沒有指定時,則指示容器在該servlet被選擇時才載入。正數的值越小,啟動該servlet的優先順序越高。)為1時候,Web應用啟動時候載入Servlet。當servlet被部署在應用伺服器中(應用伺服器中用於管理Java元件的部分被抽象成為容器)以後,由容器控制servlet的生命週期。除非特殊指定,否則在容器啟動的時候,servlet是不會被載入的,servlet只會在第一次請求的時候被載入和例項化。servlet一旦被載入,一般不會從容器中刪除,直至應用伺服器關閉或重新啟動。但當容器做記憶體回收動作時,servlet有可能被刪除。也正是因為這個原因,第一次訪問servlet所用的時間要大大多於以後訪問所用的時間。servlet在伺服器的執行生命週期為,在第一次請求(或其實體被記憶體垃圾回收後再被訪問)時被載入並執行一次初始化方法,跟著執行正式執行方法,之後會被常駐並每次被請求時直接執行正式執行方法,直到伺服器關閉或被清理時執行一次銷燬方法後實體銷燬。Java伺服器頁面(JSP)是HttpServlet的擴充套件。由於HttpServlet大多是用來響應HTTP請求,並返回Web頁面(例如HTMLXML),所以不可避免地,在編寫servlet時會涉及大量的HTML內容,這給servlet的書寫效率和可讀性帶來很大障礙,JSP便是在這個基礎上產生的。其功能是使用HTML的書寫格式,在適當的地方加入Java程式碼片斷,將程式設計師從複雜的HTML中解放出來,更專注於servlet本身的內容。JSP在首次被訪問的時候被應用伺服器轉換為servlet,在以後的執行中,容器直接呼叫這個servlet,而不再訪問JSP頁面。JSP的實質仍然是servlet。

        (1)、裝入:啟動伺服器時載入Servlet的例項; 
       (2)、初始化:web伺服器啟動時或web伺服器接收到請求時,或者兩者之間的某個時刻啟動。初始化工作有init()方法負責執行完成; 
       (3)、呼叫:從第一次到以後的多次訪問,都是隻呼叫doGet()或doPost()方法; 
       (4)、銷燬:停止伺服器時呼叫destroy()方法,銷燬例項。  

     2、filter:(必須實現javax.Servlet.Filter介面,並且必須定義以下三個方法:init(),destory(),doFilter(),空實現也行) 
         (1)、啟動伺服器時載入過濾器的例項,並呼叫init()方法來初始化例項; 
         (2)、每一次請求時都只呼叫方法doFilter()進行處理; 
         (3)、停止伺服器時呼叫destroy()方法,銷燬例項。

    3、listener:Servlet的監聽器Listener,它是實現了javax.servlet.ServletContextListener 介面的伺服器端程式,它也是隨web應用的啟動而啟動,只初始化一次,隨web應用的停止而銷燬。

           web.xml 的載入順序是:context- param -> listener -> filter -> servlet 

    4、interceptor:以struts的攔截器為例,載入了struts.xml以後,初始化相應攔截器。當action請求來時呼叫intercept方法,伺服器停止銷燬interceptor。

 

       三、職責

       1、servlet:

        建立並返回一個包含基於客戶請求性質的動態內容的完整的html頁面;
        建立可嵌入到現有的html頁面中的一部分html頁面(html片段);
        讀取客戶端發來的隱藏資料;
        讀取客戶端發來的顯示資料;
        與其他伺服器資源(包括資料庫和java的應用程式)進行通訊;
        通過狀態程式碼和響應頭向客戶端傳送隱藏資料。

       

       2、filter:

        filter能夠在一個請求到達servlet之前預處理使用者請求,也可以在離開servlet時處理http響應:
        在執行servlet之前,首先執行filter程式,併為之做一些預處理工作;
        根據程式需要修改請求和響應;
        在servlet被呼叫之後截獲servlet的執行

         3、listener:職責如概念。

          servlet2.4規範中提供了8個listener介面,可以將其分為三類,分別如下:
         第一類:與servletContext有關的listner介面。包括:ServletContextListener、ServletContextAttributeListener
         第二類:與HttpSession有關的Listner介面。包括:HttpSessionListner、HttpSessionAttributeListener、HttpSessionBindingListener、                      HttpSessionActivationListener;
         第三類:與ServletRequest有關的Listener介面,包括:ServletRequestListner、ServletRequestAttributeListener

        4、interceptor:與過濾器十分相似,通過層層攔截,處理使用者的請求和響應。

        四、幾個區別:

        1,servlet 流程是短的,url傳來之後,就對其進行處理,之後返回或轉向到某一自己指定的頁面。它主要用來在 業務處理之前進行控制.
        2,filter 流程是線性的, url傳來之後,檢查之後,可保持原來的流程繼續向下執行,被下一個filter, servlet接收等,而servlet 處理之後,不會繼續向下傳遞。filter功能可用來保持流程繼續按照原來的方式進行下去,或者主導流程,而servlet的功能主要用來主導流程。
         filter可用來進行字元編碼的過濾,檢測使用者是否登陸的過濾,禁止頁面快取等
        3, servlet,filter都是針對url之類的,而listener是針對物件的操作的,如session的建立,session.setAttribute的發生,在這樣的事件發生時做一些事情。
     可用來進行:Spring整合Struts,為Struts的action注入屬性,web應用定時任務的實現,線上人數的統計等
       4,interceptor 攔截器,類似於filter,不過在struts.xml中配置,不是在web.xml,並且不是針對URL的,而是針對action,當頁面提交action時,進行過濾操作,相當於struts1.x提供的plug-in機制,可以看作,前者是struts1.x自帶的filter,而interceptor 是struts2 提供的filter.
    與filter不同點:(1)不在web.xml中配置,而是在struts.xml中完成配置,與action在一起
                            ( 2  ) 可由action自己指定用哪個interceptor 來在接收之前做事    

        5,struts2中的過濾器和攔截器的區別與聯絡:

      (1)、攔截器是基於java反射機制的,而過濾器是基於函式回撥的。
      (2)、過濾器依賴與servlet容器,而攔截器不依賴與servlet容器。
      (3)、攔截器只能對Action請求起作用,而過濾器則可以對幾乎所有請求起作用。
      (4)、攔截器可以訪問Action上下文、值棧裡的物件,而過濾器不能。
      (5)、在Action的生命週期中,攔截器可以多次呼叫,而過濾器只能在容器初始化時被呼叫一次。

        

        五、執行流程圖:

         1、servlet:

             

          2、filter:

             

               

             

           3、listener:

             

           4、interceptor:

            

 

相關文章