Filters are Java components that allow on the fly transformations of payload and header information in both the request into a resource and the response from a resource.
這一節描述了Java Servlet v2.4 API中的一部分classes和methods,它們爲filter靜態和動態的內容提供了一個輕量級的框架。這一節也描述瞭如何在web應用中配置filters,filter的使用慣例以及它們的實現的語法。
SRV.14提供了servlet filters的API文檔。Filter的配置語法由部署描述符給出,這會在SRV13 「Deployment Descriptor」 中描述。在閱讀本章時,讀者應該把這些資源做爲參考。java
Filter是一種可反覆使用的的代碼,它能夠傳送HTTP request、response的內容,以及header信息。Filters不建立response或者是向servlets那樣響應request,但它們能夠爲request修改或適配資源,還能夠爲response修改或適配資源。
Filters能夠做用於動態或靜態內容。做爲本章節來講,提到的動態和靜態內容指的是web資源。程序員
對使用filter的開發者來講,下面是filter一些有用的特性:web
能夠在Request調用資源前訪問資源。緩存
能夠在對資源的Request執行前被調用。app
能夠針對包裝過的自定義版本request的request header及data進行修改。框架
能夠針對包裝過的自定義版本response的response header及data進行修改。ide
在資源被調用後攔截資源(The interception of an invocation of a resource after its call)。性能
以特定的順序,將零個、一個、或多個filter做用於一個servlet,一組servlet,或者靜態內容。this
Authentication filtersurl
Logging and auditing filters
Image conversion filters
Data compression filters
Encryption filters
Tokenizing filters
Filters that trigger resource access events
XSL/T filters that transform XML content
MIME-type chain filters
Caching filters
Filter模型的主要概念都將在本節討論。
應用程序開發者能夠經過實現javax.servlet.Filter接口來建立一個filter,而且要提供一個公共的無參構造方法。Filter的class文件與其餘組成web應用程序的靜態內容和其餘servlet的class一塊兒打包到Web Archive(war)中。在部署描述符中,filter經過<filter>元素來聲明,filter或filters集合能夠經過定義<filter-mapping>元素被調用。調用經過把filter映射到一個特定的servlet(經過servlet的邏輯名稱)來實現。或者經過URL pattern把filter映射到到一組servlet或者靜態內容資源上。
在部署了web application以後,request導致container去訪問web資源以前,container必須設置好filter列表,這些filter必須像下面描述的那樣做用於web resources。container必須保證自身已經把filter列表每個filter按照恰當的class實例化filter,而且調用它的init(FilterConfig config)方法。filter會經過拋出異常來代表它沒有正確地運行。若是異常的類型是UnavaliableException,container能夠檢查exception的isPermanent屬性,而且能夠選擇在下面的某個時間從新嘗試實例化。
部署描述符中聲明的filter,在container的每個JVM中,一個<filter>標籤只對應一個實例。Container來提供聲明在filter的部署描述符中的filter配置,web application的ServletContext的引用,以及初始化參數集合。
當container接收到request時,container從filter列表中取出第一個filter實例,調用filter的doFilter方法,將參數ServletRequest,ServletResponse和container使用的FilterChain對象的引用傳遞進去。
典型的狀況下,filter的doFilter方法會被實現如下所有或部分功能模式:
檢查request的headers
爲了修改request headers或者data,doFilter方法能夠把傳入的request對象用ServletRequest或HttpServletRequest接口的自定義實現包裝request對象。
爲了修改request headers或者data,doFilter方法能夠用ServletResponse或HttpServletResponse接口的自定義實現包裝request對象。
Filter能夠調用filter chain中的下一個實體。下一個實體能夠是另外一個filter,或者若是filter作的調用是部署描述符中配置的最後一個filter,那下一個實體就是目標web resource。下一個實體的調用經過調用filter chain對象上的doFilter方法完成,而且把request和response傳遞進去。
Filter chain實現的doFilter方法,經過container提供,必須找出在filter chain中的下一個實體而且調用它的doFilter方法,傳進恰當的request和response對象。
非此即彼的,filter chain能夠經過不對下一個實體進行調用的方式阻塞request,把填寫response對象的責任留給本身。
在對filter chain中下一個filter的調用以後,filter能夠檢驗response headers。
二選一的,filter有可能在執行過程當中拋出一個異常來指示一個錯誤。若是filter在執行doFilter的過程當中拋出了UnavailableException,那麼container必定不會試圖繼續執行下面的filter chain。若是exception沒有標記爲永久的話,它會在接下來的某個時間從新嘗試整個chain。
當filter chain中最後一個filter被調用時,下一個要被存取的實體就是目標servlet或者在chain中最後面的資源。
在filter實例從container的服務中被移除以前,container必須首先調用filter上的destroy方法來使filter釋放掉全部的資源而且執行其餘清理操做
過濾的核心理念是爲了包裝request或是response以即可以override行爲來執行過濾任務。在這個模型中,開發者不只有能力在request,response對象上override已有的方法,也能夠給某個filter或接下來的filter chain中的目標web資源提供適合某個特定過濾任務的新的API。例如,開發者想用高級output對象繼承response對象,這種對象是output stream或者writer,就像某種API,它容許將DOM對象回寫至client。
爲了支持這種風格的filter,container必須達到下面的要求。當filter在container filter chain的實現中調用doFilter方法時,container必須保證它傳遞給filter chain中下一個實體的request對象和response對象和當前調用的filter傳遞進doFilter方法的是同一個對象。
當調用者包裝request對象或response對象時,包裝對象也有相同的要求做用於來自servlet or a filter to RequestDispatcher.forward or RequestDispatcher.include的調用。在這種狀況下,被調用的servlet接收到的request和response對象必須和調用者servlet或filter傳入的包裝對象是相同的。
在部署描述符中,可使用<init-params>元素來關聯filter的初始化參數。在運行時,這些參數的names和values對於filter來講能夠經過filter的FilterConfig對象的getInitParameter和getInitParameterNames方法得到。另外,FilterConfig提供了對web application的ServletContext的訪問功能,以即可以裝載資源,提供日誌功能,以及對ServletContext的attribute列表的存儲。
在部署描述符中,filter使用<filter>元素定義。在這個元素中,程序員應定義如如下描述:
filter-name:用來把filter映射到一個servlet或URL
filter-class:container使用它來定義filter的類型
init-params:filter的初始化參數
還有一些可選的功能,程序員能夠定義圖標,文本的描述,and a display name for tool manipulation 。Container會按照部署描述符中所定義的,一個filter聲明對應一個java class的實例。所以,若是開發者用一樣的filter類定義了兩個filter的聲明,那麼同一個filter class就會有兩個實例被實例化。
這裏有一個filter聲明的例子:SRV.6.2.4-1.png
一旦在部署描述符中描述聲明瞭一個filter,就須要使用<filter-mapping>元素來定義filter須要做用於的內容,它們能夠是web application中的servlets和靜態resources。好比,如下的代碼片斷把Image Filter filter到了ImageServlet這個servlet:SRV.6.2.4-2.png
Filters能夠關聯至一組servlets和靜態內容,經過<url-pattern>風格的filter mapping:SRV.6.2.4-3.png
此處,Logging Filter被做用於web application中全部的servlets和靜態內容,由於每一個匹配「/*」的request URL。
當使用<url-pattern>風格的元素去執行<filter-mapping>元素的時候,container必須判斷request URL是否和<url-pattern>匹配,路徑匹配規則參見SRV.11,「Mapping Requests to Servlets」。
container在構建用來匹配某一特定request URL的filter chain時,其處理過程以下:
首先,<url-pattern>匹配filter mapping的順序和出如今部署描述符中的順序一致。
其次,<servlet-name>匹配filter mapping的順序和出如今部署描述符中的順序一致。
這樣的要求意味着container在接收到request時,會按照下面的內容處理reqeust:
根據SRV.11.2 Specifications of Mappings提到的規則來識別目標web 資源。
若是有filter與servlet name相匹配,而且web資源有<servlet-name>元素,container會依照部署描述符中聲明的狀態創建filter chain。The last filter in this chain corresponds to the last <servlet-name> matching filter and is the filter that invokes the target Web resource.
若是有filter使用<url-pattern>匹配而且根據SRV.11.2 Specification of Mapping的規則url-pattern匹配request URL,container會依照部署描述符中聲明的<url-pattern>的順序創建chain。The last filter in this chain is the filter that invokes the first filter in the <servlet-name> matching chain, or invokes the target Web resource if there are none.
高性能的web container會緩存filter chain以便它們沒必要基於每個request去計算filter chain。
在Java servlet 規範v2.4中的關於filter的新增內容是,經過配置使filter能夠在request dispatcher的forward()及include()之下被調用的能力。
經過在部署描述符中使用新標籤<dispatcher>元素,開發者能夠在filter-mapping中指出,在如下狀況出現的時候,他是否須要filter做用於request:
request直接來自client。這種狀況能夠經過給<dispatcher>元素設置value爲REQUEST來指明,或者不配置任何<dispatcher>元素。
在request dispatcher之下被執行的request表示web組件經過調用forward()來匹配<url-pattern>或者<servlet-name>。這種狀況經過給<dispatch>元素設置value爲FORWARD來聲明。
在request dispatcher之下被執行的request表示web組件經過調用forward()來匹配<url-pattern>或者<servlet-name>。這種狀況經過給<dispatch>元素設置value爲INCLUDE來聲明。
Request被SRV.9.9 Error Handling描述的錯誤頁面機制處理來匹配<url-pattern>。這種狀況經過給<dispatch>元素設置value爲ERROR來聲明。
或者以上狀況的任意組合。
舉例說明:
SRV.6.2.5-1.png
客戶端以products/...開頭的請求,都會觸發Logging Filter的調用。但並不會觸發request dispatcher的調用。再看下面的代碼:
SRV.6.2.5-2.png
客戶端對ProductServlet的請求,都不會觸發Logging Filter的調用,也不會在forward()到ProductServlet的時候被調用調用。只有request dispatcher 調用到ProductServlet而且執行include()方法時纔會觸發。
最終地,
SRV.6.2.5-3.png
would result in the Logging Filter being invoked by client requests starting /products/... and underneath a request dispatcher forward() call where the request dispatcher has path commencing /products/... 。