天天看點

Servlet 中的 Listener 的應用

Listener是一個很好的東西,能夠監聽到session,application的create,destroy,可以監聽到session,application屬性綁定的變化,考慮了一下,可以應用在"線上人數統計","資料緩存"等各個方面,

下面是整理的一些資料.

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 

我們看具體的代碼,見示例14-9。 

【程式源代碼】 

1 // ==================== Program Discription =====================

2 // 程式名稱:示例14-9 : EncodingFilter .java

3 // 程式目的:學習使用監聽器

4 // ==============================================================

5 import javax.servlet.http.*;

6 import javax.servlet.*;

7

8 public class OnLineCountListener implements HttpSessionListener,

ServletContextListener,ServletContextAttributeListener

9 {

10  private int count;

11  private ServletContext context = null;

12  

13  public OnLineCountListener()

14  {

15   count=0;

16   //setContext();

17  }

18  //建立一個session時激發

19  public void sessionCreated(HttpSessionEvent se) 

20  {

21   count++;

22   setContext(se);

23   

24  }

25  //當一個session失效時激發

26  public void sessionDestroyed(HttpSessionEvent se) 

27  {

28   count--;

29   setContext(se);

30  }

31  //設定context的屬性,它将激發attributeReplaced或attributeAdded方法

32  public void setContext(HttpSessionEvent se)

33  {

34   se.getSession().getServletContext().

setAttribute("onLine",new Integer(count));

35  }

36   //增加一個新的屬性時激發

37  public void attributeAdded(ServletContextAttributeEvent event) {

38 

39  log("attributeAdded(';" + event.getName() + "';, ';" +

40      event.getValue() + "';)");

41 

42     }

43     

44    //删除一個新的屬性時激發

45     public void attributeRemoved(ServletContextAttributeEvent event) {

46

47  log("attributeRemoved(';" + event.getName() + "';, ';" +

48      event.getValue() + "';)");

49 

50     }

51

52  //屬性被替代時激發

53     public void attributeReplaced(ServletContextAttributeEvent event) {

54 

55   log("attributeReplaced(';" + event.getName() + "';, ';" +

56       event.getValue() + "';)");

57     }

58     //context删除時激發

59      public void contextDestroyed(ServletContextEvent event) {

60 

61   log("contextDestroyed()");

62   this.context = null;

63 

64     }

65 

66     //context初始化時激發

67     public void contextInitialized(ServletContextEvent event) {

68 

69   this.context = event.getServletContext();

70   log("contextInitialized()");

71 

72     }

73     private void log(String message) {

74 

75      System.out.println("ContextListener: " + message);

76     }   

77 }

【程式注解】

在OnLineCountListener 裡,用count代表目前線上的人數,OnLineCountListener将在Web伺服器啟動時自動執行。當 OnLineCountListener構造好後,把count設定為0。每增加一個Session,OnLineCountListener會自動調用 sessionCreated(HttpSessionEvent se)方法;每銷毀一個Session,OnLineCountListener會自動調用sessionDestroyed (HttpSessionEvent se)方法。當調用sessionCreated(HttpSessionEvent se)方法時,說明又有一個客戶在請求,此時使線上的人數(count)加1,并且把count寫到ServletContext中。 ServletContext的資訊是所有用戶端共享的,這樣,每個用戶端都可以讀取到目前線上的人數。

從作用域範圍來說,Servlet的作用域有ServletContext,HttpSession,ServletRequest.

Context範圍:

ServletContextListener:

對一個應用進行全局監聽.随應用啟動而啟動,随應用消失而消失主要有兩個方法:

contextDestroyed(ServletContextEvent event) 

在應用關閉的時候調用

contextInitialized(ServletContextEvent event) 

在應用啟動的時候調用

這個監聽器主要用于一些随着應用啟動而要完成的工作,也就是很多人說的我想在容器

啟動的時候幹..........

一般來說對"全局變量"初始化,如

public void contextInitialized(ServletContextEvent event){

ServletContex sc = event.getServletContext();

sc.setAttribute(name,value);

以後你就可以在任何servlet中getServletContext().getAttribute(name);

我最喜歡用它來做守護性工作,就是在contextInitialized(ServletContextEvent event) 

方法中實作一個Timer,然後就讓應用在每次啟動的時候讓這個Timer工作:

程式代碼: 

timer = new Timer();

timer.schedule(new TimerTask(){

public void run(){

//do any things

}

},0,時間間隔);

有人說Timer隻能規定從現在開始的多長時間後,每隔多久做一次事或在什麼時間做

一次事,那我想在每月1号或每天12點做一項工作如何做呢?

你隻要設一個間隔,然後每次判斷一下當時是不是那個時間段就行了啊,比如每月一号做,那你

時間間隔設為天,即24小時一個循環,然後在run方法中判斷當時日期new Date().getDate()==1

就行了啊.如果是每天的12點,那你時間間隔設為小時,然後在run中判斷new Date().getHour()

==12,再做某事就行了.

ServletContextAttributeListener:

這個監聽器主要監聽ServletContex對象在setAttribute()和removeAttribute()的事件,注意

也就是一個"全局變量"在被Add(第一次set),replace(對已有的變量重新指派)和remove的時候.

分别調用下面三個方法:

public void attributeAdded(ServletContextAttributeEvent scab)這個方法不僅可以知道

哪些全局變量被加進來,而且可擷取容器在啟動時自動設定了哪些context變量:

public void attributeAdded(ServletContextAttributeEvent scab){

System.out.println(scab.getName());

public void attributeRemoved(ServletContextAttributeEvent scab) 

public void attributeReplaced(ServletContextAttributeEvent scab)

Session範圍:

HttpSessionListener:

這個監聽器主要監聽一個Session對象被生成和銷毀時發生的事件.對應有兩個方法:

public void sessionCreated(HttpSessionEvent se) 

public void sessionDestroyed(HttpSessionEvent se)

一般來說,一個session對象被create時,可以說明有一個新客端進入.可以用來粗略統計線上人

數,注意這不是精确的,因為這個用戶端可能立即就關閉了,但sessionDestroyed方法卻會按一定

的政策很久以後才會發生.

HttpSessionAttributeListener:

和ServletContextAttributeListener一樣,它監聽一個session對象的Attribut被Add(一個特定

名稱的Attribute每一次被設定),replace(已有名稱的Attribute的值被重設)和remove時的事件.

對就的有三個方法.

public void attributeAdded(HttpSessionBindingEvent se) 

public void attributeRemoved(HttpSessionBindingEvent se) 

public void attributeReplaced(HttpSessionBindingEvent se)

上面的幾個監聽器的方法,都是在監聽應用邏輯中servlet邏輯中發生了什麼事,一般的來說.

我們隻要完成邏輯功能,比如session.setAttribute("aaa","111");我隻要把一個名為aaa的變量

放在session中以便以後我能擷取它,我并不關心當session.setAttribute("aaa","111");發生時

我還要幹什麼.(當然有些時候要利用的),但對于下面這個監聽器,你應該好好發解一下:

HttpSessionBindingListener:

上面的監聽器都是作為一個獨立的Listener在容器中控制事件的.而HttpSessionBindingListener

對在一對象中監聽該對象的狀态,實作了該接口的對象如果被作為value被add到一個session中或從

session中remove,它就會知道自己已經作為一個session對象或已經從session删除,這對于一些非

純JAVA對象,生命周期長于session的對象,以及其它需要釋放資源或改變狀态的對象非常重要.

比如:

session.setAttribute("abcd","1111");

以後session.removeAttribute("abcd");因為abcd是一個字元中,你從session中remove後,它就會

自動被垃圾回收器回收,而如果是一個connection隻是舉例,你千萬不要加connection往session

中加入)

session.setAttribute("abcd",conn); 

以後session.removeAttribute("abcd");這時這個conn被從session中remove了,你已經無法擷取它

的句柄,是以你根本沒法關閉它.而在沒有remove之前你根本不知道什麼時候要被remove,你又無法

close(),那麼這個connection對象就死了.另外還有一些對象可以在被加入一個session時要鎖定

還要被remove時要解鎖,應因你在程式中無法判斷什麼時候被remove(),add還好操作,我可以先加鎖

再add,但remove就後你就找不到它的句柄了,根本沒法解鎖,是以這些操作隻能在對象自身中實作.

也就是在對象被add時或remove時通知對象自己回調相應的方法:

MyConn extends Connection implements HttpSessionBindingListener{

public void valueBound(HttpSessionBindingEvent se){

this.initXXX();

public void valueUnbound(HttpSessionBindingEvent se){

this.close();

session.setAttribute("aaa",new MyConn());

這時如果調用session.removeAttribute("aaa"),則觸發valueUnbound方法,就會自動關閉自己.

而其它的需要改變狀态的對象了是一樣.

本文轉自 wws5201985 51CTO部落格,原文連結:http://blog.51cto.com/wws5201985/814843,如需轉載請自行聯系原作者