Servlet、Filter、Listener、Interceptor的做用和區別

1、概念html

一、Servletjava

Servlet是一種運行服務器端的Java應用程序,具備獨立於平臺和協議的特性,而且能夠動態的生成Web頁面,它工做在客戶端請求與服務器響應的中間層。Servlet 的主要功能在於交互式地瀏覽和修改數據,生成動態Web內容。這個過程爲:程序員

1) 客戶端發送請求至服務器端;web

2) 服務器將請求信息發送至Servlet;spring

3) Servlet 生成響應內容並將其傳給服務器。響應內容動態生成,一般取決於客戶端的請求;數據庫

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

在 Web 應用程序中,一個 Servlet 在一個時刻可能被多個用戶同時訪問。這時 Web 容器將爲每一個用戶建立一個線程來執行 Servlet。若是 Servlet 不涉及共享資源的問題,沒必要關心多線程問題。但若是 Servlet 須要共享資源,須要保證 Servlet 是線程安全的。最新版本3.1,爲了簡化開發流程,Servlet 3.0 引入了註解(annotation),這使得 web 部署描述符 web.xml 再也不是必須的選擇。編程

二、Filter緩存

Filter是一個能夠複用的代碼片斷,能夠用來轉換HTTP請求、響應和頭信息。Filter不像Servlet,它不能產生一個 請求或者響應,它只是修改對某一資源的請求,或者修改從某一的響應。Servlet中的過濾器Filter是實現了javax.servlet.Filter接口的服務器端程序,主要的用途是過濾字符編碼、作一些業務邏輯判斷等。其工做原理是,只要你在web.xml 文件配置好要攔截的客戶端請求,它都會幫你攔截到請求,此時你就能夠對請求或響應(Request、Response)統一設置編碼,簡化操做;同時還可 進行邏輯判斷,如用戶是否已經登錄、有沒有權限訪問該頁面等等工做。它是隨你的web應用啓動而啓動的,只初始化一次,之後就能夠攔截相關請求,只有當你的web應用中止或從新部署的時候才銷燬。Filter可認爲是Servlet的一種「變種」,它主要用於對用戶請求HttpServletRequest進行預處理,也能夠對HttpServletResponse進行後處理,是個典型的處理鏈。它與Servlet的區別在於:它不能直接向用戶生成響應。完整的流程是:Filter對用戶請求進行預處理,接着將請求交給Servlet進行處理並生成響應,最後Filter再對服務器響應進行後處理。安全

Filter有以下幾個用處:

  • 在HttpServletRequest到達Servlet以前,攔截客戶的HttpServletRequest。

  • 根據須要檢查HttpServletRequest,也能夠修改HttpServletRequest頭和數據。

  • 在HttpServletResponse到達客戶端以前,攔截HttpServletResponse。

  • 根據須要檢查HttpServletResponse,也能夠修改HttpServletResponse頭和數據。

Filter有以下幾個種類:

  • 用戶受權的Filter:Filter負責檢查用戶請求,根據請求過濾用戶非法請求。

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

  • 負責解碼的Filter:包括對非標準編碼的請求解碼。

  • 能改變XML內容的XSLT Filter等。

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

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

  • 建Filter處理類;

  • web.xml文件中配置Filter。

下面先介紹一個簡單的記錄日誌的Filter,這個Filter負責攔截全部的用戶請求,並將請求的信息記錄在日誌中。

 

public class LogFilter implements Filter {

    

     //FilterConfig可用於訪問Filter的配置信息

    private FilterConfig config;

 

    //實現初始化方法

    public void init(FilterConfig config) {

        this.config = config;

    }

 

    //實現銷燬方法

    public void destroy() {

        this.config = null;

    }

 

    //執行過濾的核心方法

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException,ServletException {

        

   //---------下面代碼用於對用戶請求執行預處理---------

        //獲取ServletContext對象,用於記錄日誌

        ServletContext context = this.config.getServletContext();

        long before = System.currentTimeMillis();

        System.out.println("開始過濾...");

        //將請求轉換成HttpServletRequest請求

        HttpServletRequest hrequest = (HttpServletRequest) request;

        //記錄日誌

        context.log("Filter已經截獲到用戶的請求地址: " + hrequest.getServletPath());

        //Filter只是鏈式處理,請求依然放行到目的地址

        chain.doFilter(request, response);

        

  //---------下面代碼用於對服務器響應執行後處理---------

        long after = System.currentTimeMillis();

        //記錄日誌

        context.log("過濾結束");

        //再次記錄日誌

        context.log("請求被定位到" + hrequest.getRequestURI() + "所花的時間爲: " + (after - before));

    }

}

 

上面程序實現了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>   <filter-name>struts2</filter-name>   <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>    <filter-name>struts2</filter-name>    <url-pattern>/*</url-pattern>
</filter-mapping>

 

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

因此這也就是,把本身的Filter或者其餘的Filter(好比UrlRewrite的Filter)放在Struts的DispatcherFilter的前面的緣由。由於,它們須要在請求被Struts2框架處理以前,作一些前置的工做。 

當Filter被調用,而且進入了Struts2的DispatcherFilter中後,Struts2會按照在Action中配置的Interceptor Stack中的Interceptor的順序,來調用Interceptor。 

三、Listener

監聽器,從字面上能夠看出Listener主要用來監聽應用。經過listener能夠監聽web服務器中某一個執行動做,並根據其要求做出相應的響應。通俗的語言說就是在application,session,request三個對象建立消亡或者往其中添加修改刪除屬性時自動執行代碼的功能組件。好比spring 的總監聽器會在服務器啓動的時候實例化咱們配置的bean對象 、hibernate 的 session 的監聽器會監聽session的活動和生命週期,負責建立、關閉session等活動。

Servlet的監聽器Listener,它是實現了javax.servlet.ServletContextListener 接口的服務器端程序,它也是隨web應用的啓動而啓動,只初始化一次,隨web應用的中止而銷燬。主要做用是: 作一些初始化的內容添加工做、設置一些基本的內容、好比一些參數或者是一些固定的對象等等。

四、Interceptor

是在面向切面編程的,就是在你的service或者一個方法,前調用一個方法,或者在方法後調用一個方法,是基於JAVA的反射機制。好比動態代理就是攔截器的簡單實現,在你調用方法前打印出字符串(或者作其它業務邏輯的操做),也能夠在你調用方法後打印出字符串,甚至在你拋出異常的時候作業務邏輯的操做。

Servlet、Filter、Listener是配置到web.xml中(web.xml 的加載順序是:context-param -> listener -> filter -> servlet ),Interceptor不配置到web.xml中,Struts的攔截器配置到struts.xml中,Spring的攔截器配置到spring.xml中。

2、生命週期

一、Servlet

通常繼承HttpServlet(通常的,通用Servlet由javax.servlet.GenericServlet實現Servlet接口。程序設計人員能夠經過使用或繼承這個類來實現通用Servlet應用。javax.servlet.http.HttpServlet實現了專門用於響應HTTP請求的Servlet,提供了響應對應HTTP標準請求的doGet()、doPost()等方法),web.xml配置servlet時若是加上load-on-start=1,Web應用啓動時候加載Servlet。

(在servlet的配置當中,<load-onstartup>1</load-on-startup>的含義是:標記容器是否在啓動的時候就加載這個servlet。當值爲0或者大於0時,表示容器在應用啓動時就加載這個Servlet;當是一個負數時或者沒有指定時,則指示容器在該servlet被選擇時才加載。正數的值越小,啓動該servlet的優先級越高。)

當Servlet被部署在應用服務器中(應用服務器中用於管理Java組件的部分被抽象成爲容器) 之後,由容器控制Servlet的生命週期。除非特殊指定,不然在容器啓動的時候,Servlet是不會被加載的,Servlet只會在第一次請求的時候被加載和實例化。Servlet一旦被加載,通常不會從容器中刪除,直至應用服務器關閉或從新啓動。但當容器作內存回收動做時,Servlet有可能被刪除。也正是由於這個緣由,第一次訪問Servlet所用的時間要大大多於之後訪問所用的時間。

Servlet在服務器的運行生命週期爲,在第一次請求(或其實體被內存垃圾回收後再被訪問)時被加載並執行一次初始化方法,跟着執行正式運行方法,以後會被常駐並每次被請求時直接執行正式運行方法,直到服務器關閉或被清理時執行一次銷燬方法後實體銷燬。Java服務器頁面(JSP)是HttpServlet的擴展。因爲HttpServlet大可能是用來響應HTTP請求,並返回Web頁面(例如HTML、XML), 因此不可避免地,在編寫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()方法,銷燬實例。 

 二、Filter

必須實現javax.Servlet.Filter接口,而且必須定義如下三個方法:init(),destory(),doFilter(),空實現也行。 

(1)啓動服務器時加載過濾器的實例,並調用init()方法來初始化實例; 
(2)每一次請求時都只調用方法doFilter()進行處理; 
(3)中止服務器時調用destroy()方法,銷燬實例。

三、Listener

Servlet的監聽器Listener,它是實現了javax.servlet.ServletContextListener 接口的服務器端程序,它也是隨web應用的啓動而啓動,只初始化一次,隨web應用的中止而銷燬。

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

四、Interceptor

以Struts的攔截器爲例,加載了struts.xml之後,初始化相應攔截器。當action請求來時調用intercept方法,服務器中止銷燬interceptor。

 3、職責

一、Servlet

  • 建立並返回一個包含基於客戶請求性質的動態內容的完整的html頁面;

  • 建立可嵌入到現有的html頁面中的一部分html頁面(html片斷);

  • 讀取客戶端發來的隱藏數據;

  • 讀取客戶端發來的顯示數據;

  • 與其餘服務器資源(包括數據庫和java的應用程序)進行通訊;

  • 經過狀態代碼和響應頭向客戶端發送隱藏數據。

二、Filter

Filter可以在一個請求到達servlet以前預處理用戶請求,也能夠在離開Servlet時處理http響應:

  • 在執行Servlet以前,首先執行Filter程序,併爲之作一些預處理工做;

  • 根據程序須要修改請求和響應;

  • 在Servlet被調用以後截獲Servlet的執行

三、listener

職責如概念。

Servlet2.4規範中提供了8個Listener接口,能夠將其分爲三類,分別以下:

第一類:與ServletContext有關的Listener接口。包括:ServletContextListener、ServletContextAttributeListener

第二類:與HttpSession有關的Listner接口。包括:HttpSessionListener、 HttpSessionAttributeListener、HttpSessionBindingListener、                     HttpSessionActivationListener;

第三類:與ServletRequest有關的Listener接口,包括:ServletRequestListner、ServletRequestAttributeListener

四、Interceptor

與過濾器十分類似,經過層層攔截,處理用戶的請求和響應。

4、幾個區別

一、Servlet 流程是短的,url傳來以後,就對其進行處理,以後返回或轉向到某一本身指定的頁面。它主要用來在業務處理以前進行控制。

二、Filter 流程是線性的, url傳來以後,檢查以後,可保持原來的流程繼續向下執行,被下一個Filter, Servlet接收等,而Servlet 處理以後,不會繼續向下傳遞。Filter功能可用來保持流程繼續按照原來的方式進行下去,或者主導流程,而servlet的功能主要用來主導流程。

Filter可用來進行字符編碼的過濾,檢測用戶是否登錄的過濾,禁止頁面緩存等。

三、Servlet,Filter都是針對url之類的,而Listener是針對對象的操做的,如session的建立,session.setAttribute的發生,在這樣的事件發生時作一些事情。

可用來進行:Spring整合Struts,爲Struts的action注入屬性,Web應用定時任務的實現,在線人數的統計等

四、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 來在接收以前作事    

五、Struts2中的過濾器和攔截器的區別與聯繫:

(1)攔截器是基於java反射機制的,而過濾器是基於函數回調的。
(2)過濾器依賴與servlet容器,而攔截器不依賴與servlet容器。
(3)攔截器只能對Action請求起做用,而過濾器則能夠對幾乎全部請求起做用。
(4)攔截器能夠訪問Action上下文、值棧裏的對象,而過濾器不能。
(5)在Action的生命週期中,攔截器能夠屢次調用,而過濾器只能在容器初始化時被調用一次。      

5、執行流程圖

一、Servlet

   

二、Filter

 

三、Listener

四、Interceptor

相關文章
相關標籤/搜索