第六章
6 Filtering
Fileter是servlet2.3新增的部分。這一章介紹Filter類和方法,以及在web工程中的配置。
6.1什么是Fileter
Filter是重復使用的,用于變換HTTP請求和響應以及頭信息中的內容。Filter不能像servlet那樣創建
response響應,但可以修改請求和響應的內容。
6.1.1例舉一些Filter
驗證Filter
登陸,審核Filter
圖像處理Filter
數據壓縮Filter
加密Filter
XSL/T Filter
MIME Filter
6.2 主要觀念
開發者通過創建實現javax.servlet.Filter接口的類,并提供一個沒有參數的構造函數來創建一個Filter。
在描述文件中Fileter用filter表示,調用方法用filter-mapping進行配置。
6.3 Filter生命周期
在web工程發布后,在請求使引擎訪問一個web資源之前,引擎必須定位Filter列表;引擎必須確保為列
表中的每一個Filter建立了一個實例,并調用了他們的init(FilterConfig config)方法。在這過程中可以拋
出異常。
部署描述文件中定義的所有filter,僅會在引擎中產生一個實例。
引擎為filter提供了一個FilterConfig類,該類附有ServletContext和一個帶有初始化參數的set。
當引擎接受一個請求時,引擎就會調用filter列表中第一個filter的doFilter方法,把ServletRequest,
ServletResponse和FilterChain作為參數傳給它。
filter中doFilter方法典型的處理步驟是:
1)檢查請求頭信息
2)開發者創建一個實現了ServletRequest或HttpServletRequest的類,去包裝request對象,以
便修改請求的頭信息或體數據。
3)開發者創建一個實現了ServletReqponse或HttpServletResponse的類,去包裝response對
象,以便修改請求的頭信息或體數據。
4)filter可以調用鏈中的下一個實體,下一個實體是另一個filter,如果該filter是列表中最后的一
個,則它的下一個實體就是一個目標web資源。如果要調用下一個filter的doFilter方法,把
request,和response對象傳給FilterChain對象的doFilter方法中就可以了。
Filter chain 的doFilter方法是由引擎提供的,引擎在該方法中會定位filter列表中的下一個filter,
調用它的doFilter方法,把傳來的request和response對象傳給它。
5)在調用chain.doFilter之后,filter可以檢測響應的頭信息
6)在這些過程中,filter可以拋出異常。當在調用doFilter過程中拋出UnavailableException異常
時,引擎重復嘗試處理下面的filter chain的方法,如過時后還沒請求到filter chain 就會關閉對
filter chain的請求。
當filter是列表中最后一個filter時,它的下一個實體是描述配置文件中filter后面的servlet或其它
資源。
在引擎刪除一個Filter之前,引擎必須調用Filter的destroy方法,來釋放資源。
6.3.1 包裝Requests 和Responsees
過濾的中心觀念是對request或response的包裝,在這種模式下,開發者不僅可以改寫存在的方法,還
可以創建自己的新方法,用于特殊的過濾任務,例如:開發者希望擴展response對象,希望有個更高層
次的輸出流對象(writer)。
為了支持包裝模式,引擎不許保證在整個過濾鏈中,傳遞的request和response對象都是同一個對象。
6.3.2 Filter的環境
Filter的初始參數可以在描述配置文件中用init-params元素來配置,在運行時中,用FilterConfig的
getInitParameter和getInitParamesterNames方法得到配置參數。
6.3.3 Filter在web工程中的配置
在部署描述文件中:
filter-name:filter名稱
filter-class:filter類路徑
init-params:用于初始化參數
如果開發者在部署描述中為一個filter類描述了兩個定義,則引擎會創建這個filter類的兩個實例。
下面是個配置的例子:
<filter>
<filter-name>Image Filter</filter-name>
<filter-class>com.acme.ImageServlet</fiflter-class>
</filter>
一旦filter在部署描述中定義,filter-mapping就可以被定義了,filter-mapping在web應用中是定義關聯
filter的servlet和靜態資源的。
如:
<filter-mapping>
<filter-name>Image Filter</filter-name>
<servlet-name>ImageServlet</servlet-name>
</filter-mapping>
Image Filter 的 Filter就和ImageServlet 的Servlet建立了關聯。
Filter 可以和一群servlet和靜態資源關聯,用url-pattern。如:
<filter-mapping>
<filter-name>Loging Filter</filter-name>
<url-pattern>/*</url-pattern>
<filter-mapping>
引擎建立特殊請求URI的Filter鏈的順序是:
1)url-pattern映射fiter-mapping的順序和描述文件中定義的順序是一樣的。
2)servlet-name映射filter-mapping的順序和描述文件中定義的順序是一樣的。
這種需求要求引擎在接受請求時:
.識別符合SRV.11.2規則的web資源。
.如果一些filter是servlet和有servlet-name的web資源匹配的,引擎就會創建一個和描述文件中
映射servlet-name的順序一樣的filter鏈。
.如果一些filter是rul-pattern關聯的,引擎就會創建一個和描述文件中映射url-pattern的順序一
樣的efilter鏈。
一個高性能的web容器將會緩存filter鏈。
第七章 Sessions
超文本傳輸協議(HTTP)是無狀態的協議。要建立一個有效的web應用,客戶端之間的通信是需要
的。有很多會話跟蹤的策略,
但是直接使用這些技術都很難使用。servlet規范中提供了一個簡單的HttpSession接口,不需要開發者
關心會話跟蹤的具體細節。
7.1 會話跟蹤機制
下面描述了幾種會話的跟蹤機制
7.1.1 Cookies
HTTP cookies是最常用的會話跟蹤機制,所有的servlet引擎都應該支持這種方法。
引擎發送一個cookie到客戶端,客戶端就會在以后的請求中把這個cookie返回給服務器。用戶會話跟蹤
的cookie的名字必須是JSESSIONID
7.1.2 SSL Sessions
在安全套接字層,加密技術用在了HTTPS協議,從一個客戶端來的多個請求允許用一個含糊的標識,
servlet引擎就用這個數據定義一個Session。
7.1.3 URL重寫
URL重寫是最低性能的通用會話跟蹤方法。當一個客戶端不能接受cookie時,URL重寫就會作為基本的
會話跟蹤方法;URL重寫包括一個附加的數據,一個session id,這樣的URL會被引擎解析和一個session
相關聯。一個session id是作為URL的一個被編碼的參數傳輸的,這個參數名字必須是jsessionid.如下面
的例子:
http://www.myserver.com/catalog/index.html;jsessionid=1234
7.1.4 會話的完整性
一個web容器必須支持HTTP 會話。而當cookies方法不被支持時,通常使用URL重寫方法。
7.2 創建一個會話
servlet設計者必須考慮到一個客戶端不能加入session的情況。
7.3 會話范圍
HttpSession對象只在應用程序級有效,通常用于session的cookie可以服務于不同的上下文,但一個
HttpSession實例只服務于一個會話。舉個例子:如一個servlet A用RequestDispatcher去調用另一個web
應用中的另一個servlet B,用于A和B的會話一定是兩個不同的會話。
7.4 Session屬性的邦定
一個servlet可以通過一個name邦定一個對象到HttpSession實例中;只要獲得包含同一個會話的請求對
象,任何邦定到會話中的對象在同一個ServletContext中對于其它的servlet都是可用的。
當把一個對象放入session或從session刪除時可能要通知其它對象,這些信息能夠被實現了
HttpSessionBindingListener接口的對象獲得,這個接口定義了一下的一些方法。
valueBound
valueUnbound
valueBound方法在HttpSession接口調用getAttribute方法獲得一個有效的對象之前調用。valueUnbound
方法在HttpSession接口調用getAttribute方法獲得一個不再有效的對象后調用。
7.5 會話超時
在HTTP協議中,當客戶端不再有效時,沒有清楚的定義終止信號。這就意味著通常只能采用時間超時
來表明客戶端不再有效。
默認的超時時間是servlet引擎定義的,通過HttpSession的getMaxInactiveInterval方法可以得到超時的
時間;開發者可用用setMaxInactiveInterval方法來設置超時的時間,以秒定義的。如果一個session的
超時時間被設置為-1,則這個session將永遠有效。
7.6 最后訪問時間
在當前的請求中用HttpSession接口的getLastAccessedTime可以獲得最后一次訪問session的時間。
7.7 重要session
7.7.1 線程問題
在一個可以配置的應用中,所有的請求都是一個會話的一部分,引擎一定能夠取出通過setAttribute或
putValue放入HttpSession對象中的對象。注意以下的情況:
.引擎一定能夠訪問實現了Serializable接口的對象。
.引擎可以選擇存儲HttpSession對象中指定的對象,如EJB組件和事務。
.引擎能夠監聽到會話的變動。
如果放入session中的對象沒有被Seializable或沒有效,servlet可以拋出IllegalArgumentException;如果
引擎不支持Session存儲對象的機制,引擎一定會拋出IllegalArgumentException。
這些限制意味著,在一個分布式引擎中,不會有額外的并發問題。
如果引擎為了service的品質持續化或遷移session,使用本地持續化的HttpSession或它的屬性是不受限
制的,開發者要想確保放入session中的屬性對象能夠可用,最好對象實現Serializable接口。
在遷移一個session時引擎必須通知session中實現了HttpSessinActivationListener的屬性對象,必須通知
在序列化前鈍化的或序列化后激活的session的監聽器。
開發分布式的開發者應該清楚的是,一旦引擎運行在超過一個JVM的時候,就不能用static 表明變量來
存儲應用狀態,應該用EJB或數據庫賴存儲。
7.7.3客戶端
因為cookies或SSL證書都是被web瀏覽器訪問過程控制的,與任何特殊的window瀏覽器是沒有關系的。
所以從所有window客戶端到一個servlet引擎的請求是同一個會話的一部分。最好是開發者總是設想所
有的window客戶端是一起參與同一個會話的。