Java中Filter、Listener,拦截器的学习,listener、 filter、servlet 加载顺序及其详解
Filter
filter可認為是Servlet的一種“變種”,它主要用于對用戶請求進行預處理,也可以對HttpServletResponse進行后處理,是個典型的處理鏈。它與Servlet的區別在于:它不能直接向用戶生成響應。完整的流程是:Filter對用戶請求進行預處理,接著將請求交給Servlet進行處理并生成響應,最后Filter再對服務器響應進行后處理。
Filter有如下幾個用處。
- 在HttpServletRequest到達Servlet之前,攔截客戶的HttpServletRequest。
- 根據需要檢查HttpServletRequest,也可以修改HttpServletRequest頭和數據。
- 在HttpServletResponse到達客戶端之前,攔截HttpServletResponse。
- 根據需要檢查HttpServletResponse,也可以修改HttpServletResponse頭和數據。
過濾器的基本原理
在Servlet作為過濾器使用時,它可以對客戶的請求進行處理。處理完成后,它會交給下一個過濾器處理,這樣,客戶的請求在過濾鏈里逐個處理,直到請求發送到目標為止。例如,某網站里有提交“修改的注冊信息”的網頁,當用戶填寫完修改信息并提交后,服務器在進行處理時需要做兩項工作:判斷客戶端的會話是否有效;對提交的數據進行統一編碼。這兩項工作可以在由兩個過濾器組成的過濾鏈里進行處理。當過濾器處理成功后,把提交的數據發送到最終目標;如果過濾器處理不成功,將把視圖派發到指定的錯誤頁面。
下面先介紹一個簡單的記錄日志的Filter,這個Filter負責攔截所有的用戶請求,并將請求的信息記錄在日志中。
[java]?view plaincopy上面程序實現了doFilter()方法,實現該方法就可實現對用戶請求進行預處理,也可實現對服務器響應進行后處理——它們的分界線為是否調用了chain.doFilter(),執行該方法之前,即對用戶請求進行預處理;執行該方法之后,即對服務器響應進行后處理。
Filter生命周期同Servlet 的生命周期一樣
??? (1) 初始化
在下列時刻裝入 Servlet:
如果已配置自動裝入選項,則在啟動服務器時自動裝入
在服務器啟動后,客戶機首次向 Servlet 發出請求時
重新裝入 Servlet 時裝入 Servlet 后,服務器創建一個 Servlet 實例并且調用 Servlet 的 init() 方法。在初始化階段,Servlet 初始化參數被傳遞給 Servlet 配置對象。
(2) 請求處理
對于到達服務器的客戶機請求,服務器創建特定于請求的一個“請求”對象和一個“響應”對象。服務器調用 Servlet 的 service() 方法,該方法用于傳遞“請求”和“響應”對象。service() 方法從“請求”對象獲得請求信息、處理該請求并用“響應”對象的方法以將響應傳回客戶機。service() 方法可以調用其它方法來處理請求,例如 doGet()、doPost() 或其它的方法。
?? (3) 終止
當服務器不再需要 Servlet, 或重新裝入 Servlet 的新實例時,服務器會調用 Servlet 的 destroy() 方法。
Listener
它是基于觀察者模式設計的,Listener 的設計對開發 Servlet 應用程序提供了一種快捷的手段,能夠方便的從另一個縱向維度控制程序和數據。目前 Servlet 中提供了 5 種兩類事件的觀察者接口,它們分別是:4 個 EventListeners 類型的,ServletContextAttributeListener、ServletRequestAttributeListener、ServletRequestListener、HttpSessionAttributeListener 和 2 個 LifecycleListeners 類型的,ServletContextListener、HttpSessionListener。如下圖所示:
?
Listener是Servlet的監聽器,它可以監聽客戶端的請求、服務端的操作等。通過監聽器,可以自動激發一些操作,比如監聽在線的用戶的數量。當增加一個HttpSession時,就激發sessionCreated(HttpSessionEvent se)方法,這樣就可以給在線人數加1。常用的監聽接口有以下幾個:
ServletContextAttributeListener監聽對ServletContext屬性的操作,比如增加、刪除、修改屬性。
ServletContextListener監聽ServletContext。當創建ServletContext時,激發contextInitialized(ServletContextEvent sce)方法;當銷毀ServletContext時,激發contextDestroyed(ServletContextEvent sce)方法。
HttpSessionListener監聽HttpSession的操作。當創建一個Session時,激發session Created(HttpSessionEvent se)方法;當銷毀一個Session時,激發sessionDestroyed (HttpSessionEvent se)方法。
HttpSessionAttributeListener監聽HttpSession中的屬性的操作。當在Session增加一個屬性時,激發attributeAdded(HttpSessionBindingEvent se) 方法;當在Session刪除一個屬性時,激發attributeRemoved(HttpSessionBindingEvent se)方法;當在Session屬性被重新設置時,激發attributeReplaced(HttpSessionBindingEvent se) 方法。
下面我們開發一個具體的例子,這個監聽器能夠統計在線的人數。在ServletContext初始化和銷毀時,在服務器控制臺打印對應的信息。當ServletContext里的屬性增加、改變、刪除時,在服務器控制臺打印對應的信息。
要獲得以上的功能,監聽器必須實現以下3個接口:
HttpSessionListener
ServletContextListener
ServletContextAttributeListener
?
例子:
[java]?view plaincopy
listener、 filter、servlet 加載順序
在項目中總會遇到一些關于加載的優先級問題,近期也同樣遇到過類似的,所以自己查找資料總結了下,下面有些是轉載其他人的,畢竟人家寫的不錯,自己也就不重復造輪子了,只是略加點了自己的修飾。
首先可以肯定的是,加載順序與它們在 web.xml 文件中的先后順序無關。即不會因為 filter 寫在 listener 的前面而會先加載 filter。最終得出的結論是:listener -> filter -> servlet
??????? 同時還存在著這樣一種配置節:context-param,它用于向 ServletContext 提供鍵值對,即應用程序上下文信息。我們的 listener, filter 等在初始化時會用到這些上下文中的信息,那么 context-param 配置節是不是應該寫在 listener 配置節前呢?實際上 context-param 配置節可寫在任意位置,因此真正的加載順序為:context-param -> listener -> filter -> servlet
攔截器攔截器,在AOP(Aspect-Oriented Programming)中用于在某個方法或字段被訪問之前,進行攔截然后在之前或之后加入某些操作。攔截是AOP的一種實現策略。?
在Webwork的中文文檔的解釋為——攔截器是動態攔截Action調用的對象。它提供了一種機制可以使開發者可以定義在一個action執行的前后執行的代碼,也可以在一個action執行前阻止其執行。同時也是提供了一種可以提取action中可重用的部分的方式。?
談到攔截器,還有一個詞大家應該知道——攔截器鏈(Interceptor Chain,在Struts 2中稱為攔截器棧 Interceptor Stack)。攔截器鏈就是將攔截器按一定的順序聯結成一條鏈。在訪問被攔截的方法或字段時,攔截器鏈中的攔截器就會按其之前定義的順序被調用。
攔截器的實現原理:?
大部分時候,攔截器方法都是通過代理的方式來調用的。Struts 2的攔截器實現相對簡單。當請求到達Struts 2的ServletDispatcher時,Struts 2會查找配置文件,并根據其配置實例化相對的攔截器對象,然后串成一個列表(list),最后一個一個地調用列表中的攔截器。
攔截器與過濾器的區別 :
1. 攔截器是基于Java的反射機制的,而過濾器是基于函數回調。
2. 攔截器不依賴與servlet容器,過濾器依賴與servlet容器。?
3. 攔截器只能對action請求起作用,而過濾器則可以對幾乎所有的請求起作用。
4. 攔截器可以訪問action上下文、值棧里的對象,而過濾器不能訪問。
5. 在action的生命周期中,攔截器可以多次被調用,而過濾器只能在容器初始化時被調用一次
總結
以上是生活随笔為你收集整理的Java中Filter、Listener,拦截器的学习,listener、 filter、servlet 加载顺序及其详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用Navicat连接Oracle数据库时
- 下一篇: JavaSE学习之IO流使用技巧