天天看點

Java Filter 過濾機制詳解



一、什麼是Filter

         Filter 技術是servlet 2.3 新增加的功能.servlet2.3是sun公司與2000年10月釋出的,它的開發者包括許多個人和公司團體,充分展現了sun公司所倡導的代碼開放性原則.由于衆多的參與者的共同努力,servlet2.3比以往功能都強大了許多,而且性能也有了大幅提高.

它新增加的功能包括:

1. 應用程式生命周期事件控制;

2. 新的國際化;

3. 澄清了類的裝載規則;

4. 新的錯誤及安全屬性;

5. 不贊成使用HttpUtils 類;

6. 各種有用的方法;

7. 闡明并擴充了幾個servlet DTD;

8. filter功能.

其中最重要的就是filter功能.它使使用者可以改變一個request和修改一個response. Filter 不是一個servlet,它不能産生一個response,它能夠在一個request到達servlet之前預處理request,也可以在離開servlet時處理response.換種說法,filter其實是一個”servlet chaining”(servlet 鍊).一個filter 包括:

    1,在servlet被調用之前截獲。

    2,在servlet被調用之前檢查servlet request。

    3,根據需要修改request頭request資料。

    4,根據需要修改response頭和response資料。

    5,在servlet被調用之後截獲。

你能夠配置一個filter到一個或多個servlet;單個servlet或servlet組能夠被多個filter 使用.幾個實用的filter 包括:使用者辨認filter,日志filter,稽核filter,加密filter,符号filter,能改變xml内容的XSLT filter等.

一個filter必須實作javax.servlet.Filter接口定義的三個方法: doFilter、init和destroy。(在三個方法在後面後有詳細的介紹).

二、Filter體系結構

2.1、Filter工作原理(執行流程)

當用戶端發出Web資源的請求時,Web伺服器根據應用程式配置檔案設定的過濾規則進行檢查,若客戶請求滿足過濾規則,則對客戶請求/響應進行攔截,對請求頭和請求資料進行檢查或改動,并依次通過過濾器鍊,最後把請求/響應交給請求的Web資源處理。請求資訊在過濾器鍊中可以被修改,也可以根據條件讓請求不發往資源處理器,并直接向客戶機發回一個響應。當資源處理器完成了對資源的處理後,響應資訊将逐級逆向傳回。同樣在這個過程中,使用者可以修改響應資訊,進而完成一定的任務。

上面說了,當一個請求符合某個過濾器的過濾條件時該請求就會交給這個過濾器去處理。那麼當兩個過濾器同時過濾一個請求時誰先誰後呢?這就涉及到了過濾鍊FilterChain。

所有的奧秘都在Filter的FilterChain中。伺服器會按照web.xml中過濾器定義的先後循序組裝成一條鍊,然後一次執行其中的doFilter()方法。(注:這一點Filter和Servlet是不一樣的)。執行的順序就如下圖所示,執行第一個過濾器的chain.doFilter()之前的代碼,第二個過濾器的chain.doFilter()之前的代碼,請求的資源,第二個過濾器的chain.doFilter()之後的代碼,第一個過濾器的chain.doFilter()之後的代碼,最後傳回響應。

Java Filter 過濾機制詳解

通常我們所通路的資源是一個servlet或jsp頁面,而jsp其實是一個被封裝了的servlet(每個jsp執行前都會被轉化為一個标準的servlet),于是我們就可以統一地認為我們每次通路的都是一個Servlet,而每當我們通路一個servlet時,web容器都會調用該Servlet的service方法去處理請求。而在service方法又會根據請求方式的不同(Get/Post)去調用相應的doGet()或doPost()方法,實際處理請求的就是這個doGet或doPost方法。寫過servlet的朋友都應該知道,我們在doGet(或doPost)方法中是通過response.getWriter()得到用戶端的輸出流對象,然後用此對象對客戶進行響應。

到這裡我們就應該了解了過濾器的執行流程了:

執行第一個過濾器的chain.doFilter()之前的代碼——>第二個過濾器的chain.doFilter()之前的代碼——>……——>第n個過濾器的chain.doFilter()之前的代碼——>所請求servlet的service()方法中的代碼——>所請求servlet的doGet()或doPost()方法中的代碼——>第n個過濾器的chain.doFilter()之後的代碼——>……——>第二個過濾器的chain.doFilter()之後的代碼——>第一個過濾器的chain.doFilter()之後的代碼。

2.2、 Servlet過濾器API

Servlet過濾器API包含了3個接口,它們都在javax.servlet包中,分别是Filter接口、FilterChain接口和FilterConfig接口。

(1) public void init(FilterConfig filterConfig) throws   ServletException.

      當開始使用servlet過濾器服務時,Web容器調用此方法一次,為服務準備過濾器;然後在需要使用過濾器的時候調用doFilter(),傳送給此方法的FilterConfig對象,包含servlet過濾器的初始化參數。

(2)public void doFilter(ServletRequestrequest,ServletResponse response,FilterChainchain)

                     throws java.io.IOException,ServletException.

         每個過濾器都接受目前的請求和響應,且FilterChain過濾器鍊中的過濾器(應該都是符合條件的)都會被執行。doFilter方 法中,過濾器可以對請求和響應做它想做的一切,通過調用他們的方法收集資料,或者給對象添加新的行為。過濾器通過傳送至 此方法的FilterChain參數,調用chain.doFilterO将控制權傳送給下一個過濾器。當這個調用傳回後,過濾器可以在它的 Filter方法的最後對響應做些其他的工作。如果過濾器想要終止請求的處理或得到對響應的完全控制,則可以不調用下一個過濾 器,而将其重定向至其它一些頁面。當鍊中的最後一個過濾器調用chain.doFilterO方法時,将運作最初請求的Servlet。

(3)public void destroy()

        一旦doFilter()方法裡的所有線程退出或已逾時,容器調用此方法。伺服器調用destory()以指出過濾器已結束服務,用于釋

放過濾器占用的資源。

2.2.2public interface FilterChain

public voiddoFilter(ServletRequest request,ServletResponseresponse)

    thlows java.io.IOException,ServletException

      此方法是由Servlet容器提供給開發者的,用于對資源請求過濾鍊的依次調用,通過FilterChain調用過濾鍊中的下一個過濾  器,如果是最後一個過濾器,則下一個就調用目标資源。

2.2.3public interface FilterConfig

FilterConfig接口檢索過濾器名、初始化參數以及活動的Servlet上下文。該接口提供了以下4個方法:

     (1)public java.Lang.String getFilterName()傳回web.xml部署檔案中定義的該過濾器的名稱。

     (2)public ServletContext getServletContext()傳回調用者所處的servlet上下文。

     (3)public java.1ang.StringgetlnitParameter(java.1ang.String name)傳回過濾器初始化參數值的字元串形式,當參數不存在時, 傳回nul1.name是初始化參數名。

(4)publicjava.util.Enumeration getlnitParameterNames()以Enumeration形式傳回過濾器所有初始化參數值,如果沒有初始化參數,傳回為空。

      2.3、過濾器相關接口工作流程

從程式設計的角度看,過濾器類将實作Filter接口,然後使用這個過濾器類中的FilterChain和FilterConfig接口。該過濾器類的

— 個引用将傳遞給FilterChain對象,以允許過濾器把控制權傳遞給鍊中的下一個資源。FilterConfig對象将由容器提供給過濾器,以允許通路該過濾器的初始化資料。

2.4、過濾器配置

過濾器通過Web應用程式中的配置描述符web.xml檔案中的明,包括部分:

過濾器定義,由<filter>元素表示,主要包括<filter-name>和<filter-class>兩個必須的子元素和<icon>、<init-param>,<display-name>,<description>這4個可選的子元素。

<filter-name>子元素定義了—個過濾器的名字,<filter-class>指定了由容器載入的實際類,<init-param>子元素為過濾器提供初始化參數。

<filter-mapping>主要由<filter-name>,<servlet-name>和<url-pattem>子元素組成。<servlet-name>将過濾器映射到一個或多個Servlet上,<url-pattem>将過濾器映射到—個或多個任意特征的URL的JSP頁面。

三、應用執行個體

從上面分析可知,實作Servlet過濾器,需要兩步:

第一步開發過濾器,設計—個實作Fiker接口的類;

第二步通過web.xml配置過濾器,實作過濾器和Servlet、JSP頁面之間的映射。

注意:chain.doFilterO語句以前的代碼用于對客戶請求的處理;以後的代碼用于對響應進行處理。

配置過濾器

    在應用程式Web—INF目錄下的web.xml描述符檔案中添加以下代碼:

 <!-- 請求攔截過濾器 -->

 <filter>

  <filter-name>requestFilter</filter-name> //過濾器名稱

  <filter-class>org.eredlab.g4.rif.util.RequestFilter</filter-class>//實作過濾器的類

  <init-param>  

   <param-name>enabled</param-name>//過濾器初始化參數名enabled

   <param-value>true</param-value> 

  </init-param>

 </filter>

 <filter-mapping>                  //過濾器映射規則

  <filter-name>requestFilter</filter-name>

  <url-pattern>*.ered</url-pattern>  //映射到web應用根目錄下的所有jsp檔案

 </filter-mapping>

四、 結束語

Servlet過濾器功能強大,應用廣泛,除支援Servlet和JSP頁面的基本功能,比如日志記錄、性能、安全、會話處理、XSLT轉換等外,在J2EE應用程式中使用Java Servlet過濾器轉換其輸出,以便相容任何類型用戶端也表現出了很好的前景。Servlet過濾器能夠偵測到來自使用WAP協定(無線應用協定)的移動用戶端的呼叫,并且将答複内容轉換成WML(無線标記語言)格式。Servlet過濾器也能檢測到來自iMode無線客戶的呼叫,并将其轉變成cHTML(緊湊HTML)格式等等。因而,深刻了解Servlet過濾器的工作機制,熟練掌握程式設計技術,在實際的開發過程中,可以不斷地發現新的用途,增強元件的可重用性,提高Web應用程式的可維護性。

繼續閱讀