[Servlet] Listener - 在特定的時候執行程式


上一篇提到Servlet的一個高級特性Filter之後,我們這邊也要來介紹一下另外一個高級特性,那就是Listener。

前言

上一篇提到Servlet的一個高級特性Filter之後,我們這邊也要來介紹一下另外一個高級特性,那就是Listener。

什麼是Listener

Listener和我們在.Net裡面說的Event是差不多的概念。在Asp .net Webform你可以為一個按鈕註冊一個click事件,那麼當按鈕被按了以後,事件裡面的程式碼就會被執行。

Listener是一樣的概念,他有幾個事件可以去被Listen,而只要條件觸發了,那麼裡面的程式碼就會執行。

Listener提供了一種監控機制,讓我們能夠在某些情況發生的時候,執行我們要的程式碼。

什麼能夠被Listen

基本上來說,有三種存放位置被變動以後可以觸發Listener,它們分別是:request,session和Context。

而有兩種情景會被觸發:

  1. 當存放位置本身在創建和銷毀的時候觸發
  2. 當存放位置的內容在創建、銷毀和修改的時候觸發。

Listener的基本結構

基本上,Listener都是Interface,而只要有class實作那個Interface,並且註冊到web.xml裡面就可以。

基本Listener是一種廣泛的,意思是只要符合條件的情況下Listener都會被觸發,不過有兩個Listener比較特別,是只作用於實作的那個Class,而那兩個Listener是不需要註冊在web.xml就可以有效的。

存放位置本身在創建和銷毀的時候觸發

總共三個存放位置,而每一個能夠監聽啟動和銷毀的情況,他們都很相似名稱都是xxxListener,xxx代表每一個存放位置,所以就一起介紹。

ServletRequestListener

一樣兩個方法:

  1. requestInitialized(ServletRequestEvent ev) - 當request進來的時候會執行
  2. requestDestroyed(ServletRequestEvent ev) - 當request處理完要銷毀前執行
這邊需要注意的是,假設request包含在伺服器的圖片,那麼每一個圖片都會觸發requestInitialized()。

HttpSessionListener

此Interface有兩個方法:

  1. sessionCreated(HttpSessionEvent ev) - 當Session被建立起來的時候
  2. sessionDestroyed(HttpSessionEvent ev) - 當Session time out或者被執行session.invalidate()。基本上就是被銷毀前執行

ServletContextListener

此Interface也是兩個方法:

  1. contextInitialized(ServletContextEvent ev) - 當Web container啟動或者部署WAR的時候執行
  2. contextDestroyed(ServletContextEvent ev) - 當Web container要停止的時候

當存放內容在創建、銷毀和修改的時候觸發

一樣,結構非常相似,Interface名稱都是xxxAttributeListener。xxx分別代表ServletRequest、HttpSession和ServletContext。

而它們關注是內容變化,因此個自有三個方法,也都是xxxAdded()、xxxReplaced()和xxxRemoved()。xxx分別是:request、session和context。

只Listen有實作的Class

上面的xxxAttributeListener是針對所有只要有動到那三個儲存空間的動作都會被觸發,不過這邊有兩個特別的Listener只會在有實作的Class觸發。

HttpSessionBindingListener

這個有兩個方法,valueBound(HttpSessionBindingEvent ev)和valueUnbound(HttpSessionBindingEvent ev)。

有實作這個interface的class,只要是這個class的object被放入Session(呼叫valueBound())和從Session銷毀(呼叫valueUnbound())都會呼叫對應的方法。

這邊或許有一個問題是,同樣的功能我不是能夠用HttpSessionAttributeListener的sessionAdded()和sessionRemoved()取得嗎?

使用HttpSessionBindingListener的好處是:

  1. 不需要做type conversion - 因為你知道進來的一定是這個class type
  2. 如果只是要監控這一個Class,那麼比較方便

當然壞處就是high coupling。

HttpSessionActivationListener

這個其實我還不是很清楚用途。我只知道在Session裡面的物件如果都是Serializable,那麼就不需要擔心,不然的話就要透過這個Listener在sessionWillPassivate( HttpSessionEvent ev)的時候把它存起來,然後再sessionDidActivate(HttpSessionEvent ev)把它讀出來。

好像主要是為了當Session需要在JVM傳遞的時候用到。

配置Listener

除了那兩個只會影響到有事做Class的Listener之外,其他的Listener都需要在Web.xml裡面註冊。這有個好處,哪天如果不需要了,把註冊的地方從web.xml刪除就沒有作用了。

Listener通常放在Servlet的上面。

註冊格式很簡單:

<listener>
<listener-class>{fully qualified class name}</listener-class>
</listener>

Listener的幾個使用情景

Listener有很多用途,這邊我只舉例幾個常用的。

初始化整個網站使用的參數

還記得我們可以再web.xml利用Context-Param的方式設定預設參數。如果我們網站很常讀取這些內容,可以再Web Container啟動的時候把它們讀進memory裡面,減少之後的IO。

這個時候就會用到ServletContextListener的contextInitialized()來達到。

首先定義一個專門用來裝值的class:

package mine;
public class Config {
	
	public static String ipAddress;
	
	public static String port;

}

然後定義一個ServletContextListener:

...
public class ContextInitListener implements ServletContextListener {

@Override
public void contextInitialized(ServletContextEvent ev) {

	ServletContext context = ev.getServletContext();
	
	mine.Config.ipAddress = context.getInitParameter("ipAddress");
	mine.Config.port = context.getInitParameter("port");
}
...

在註冊到web.xml裡面:

<listener>
	<listener-class>listener.ContextInitListener</listener-class>
</listener>

之後在任意頁面都可以取得Config裡面的值。

記錄目前瀏覽人數

我們其實可以透過HttpSessionListener來知道目前瀏覽網站的人數。只要sessionDestroy()表示有人離開,而sessionCreate()表示有人進來。

結語

透過這一篇的介紹,希望對於Listener的使用有比較瞭解。

Filter和Listener的搭配使用讓我們可以達到很多效果,而且這些還是low coupling的方式。假設如果上線了客戶和你說不想要/想要某些功能是需要修改到所有頁面才能做到(例如記錄頁面瀏覽人次),這個時候註冊/反註冊filter或者listener都是非常簡單的,只要修改web.xml裡面就能達到。

Dotblogs 的標籤:

Google+

創用 CC 授權條款
Alan Tsai 的隨手筆記Alan Tsai製作,以創用CC 姓名標示 4.0 國際 授權條款釋出。