a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 219|回复: 3

[JAVA] 2011年计算机等考二级JAVA学习精华整理(71)

[复制链接]
发表于 2012-7-31 22:04:26 | 显示全部楼层 |阅读模式
 2.7 Servlet中的Listener的应用  由于工作需要,最近在找一些解决方案,发现Listener是一个很好的东西,
- v- C, l8 a7 S# k  能够监听到session,application的create,destroy,可以监听到session,application
% m/ y5 `% m% G, E" e3 D/ j9 n  属性绑定的变化,考虑了一下,可以应用在"在线人数统计","数据缓存"等各个方面,- }" @" O1 D- O
  下面是整理的一些资料./ C- u/ X. b; p0 p2 g( h9 t9 k+ D
  Listener是Servlet的监听器,它可以监听客户端的请求、服务端的操作等。通过监听器,可以自动激发一些操作,比如监听在线的用户的数量。当增加一个HttpSession时,就激发sessionCreated(HttpSessionEvent se)方法,这样就可以给在线人数加1。常用的监听接口有以下几个:
& C9 U. ~. @+ K: Z  k0 c  ServletContextAttributeListener监听对ServletContext属性的操作,比如增加、删除、修改属性。% O1 ~  D; X2 m' z3 D
  ServletContextListener监听ServletContext。当创建ServletContext时,激发contextInitialized(ServletContextEvent sce)方法;当销毁ServletContext时,激发contextDestroyed(ServletContextEvent sce)方法。- j. Y8 n$ H* Z8 L- X
  HttpSessionListener监听HttpSession的操作。当创建一个Session时,激发session Created(HttpSessionEvent se)方法;当销毁一个Session时,激发sessionDestroyed (HttpSessionEvent se)方法。$ n0 a3 D! ?5 O; w0 U
  HttpSessionAttributeListener监听HttpSession中的属性的操作。当在Session增加一个属性时,激发attributeAdded(HttpSessionBindingEvent se) 方法;当在Session删除一个属性时,激发attributeRemoved(HttpSessionBindingEvent se)方法;当在Session属性被重新设置时,激发attributeReplaced(HttpSessionBindingEvent se) 方法。4 T7 x- ~+ E  V" s' x. `
  下面我们开发一个具体的例子,这个监听器能够统计在线的人数。在ServletContext初始化和销毁时,在服务器控制台打印对应的信息。当ServletContext里的属性增加、改变、删除时,在服务器控制台打印对应的信息。
3 B+ P4 z- `- ]2 O6 ]  要获得以上的功能,监听器必须实现以下3个接口:' V+ P' s! e% O) i
  HttpSessionListener  `/ J% z( I3 I# ^/ r
  ServletContextListener
9 n/ y8 W3 j0 J4 l  ServletContextAttributeListener
# `% Q( Y+ u- a( s" ~( c6 V  我们看具体的代码,见示例14-9。
! s& x9 Z1 ?2 D0 L& M9 @$ F) _  【程序源代码】
: P$ E. E/ }) z, M/ z  1 // ==================== Program Discription =====================
, u! F' v; p; z; F  2 // 程序名称:示例14-9 : EncodingFilter .java1 g' V, w$ G7 r# v
  3 // 程序目的:学习使用监听器) r& r' e5 h9 t  o/ a# _
  4 // ==============================================================
- Y' b; l8 ?3 z: i6 q, x) {  5 import javax.servlet.http.*;& p( B- q9 F: q" f) b" @' S0 }
  6 import javax.servlet.*;  w6 C$ g% }  K! n) H# k2 z) f9 P
  7
: C0 d; p8 u2 Q" p2 }  8 public class OnLineCountListener implements HttpSessionListener,
+ U& R  W+ U6 t  ServletContextListener,ServletContextAttributeListener; a. w/ X; [9 [6 o5 B
  9 {
2 Y4 }" ^8 u9 d  10 private int count;2 u) x; z2 s  M7 H5 j' ]* Z* ~6 }7 \
  11 private ServletContext context = null;
1 S! F: c( K$ [0 [: \  12
0 T" G: d1 {# X2 f- [6 ^, Q  13 public OnLineCountListener()
7 f8 V# G1 ~9 E  14 {0 U. C0 k/ m& A7 \; |/ [
  15 count=0;
. g/ Z9 H/ p% J0 W9 T  j  16 //setContext();
* }6 L5 r7 z0 f$ C1 O  17 }
0 Z) i) D4 y0 i& P* k  18 //创建一个session时激发8 U$ U3 k6 \  s9 Q, M
  19 public void sessionCreated(HttpSessionEvent se)& A4 K. M, p/ G1 i
  20 {  O6 e6 {& l7 M
  21 count++;
/ O$ F# Q; G4 ~8 [- K. k! |. Z  22 setContext(se);
" t( O' v. e1 x* i  23: C( t8 F; P6 ~
  24 }
# f6 j, e+ X' L$ ]+ ~  25 //当一个session失效时激发
回复

使用道具 举报

 楼主| 发表于 2012-7-31 22:04:27 | 显示全部楼层

2011年计算机等考二级JAVA学习精华整理(71)

26 public void sessionDestroyed(HttpSessionEvent se)  27 {
0 M8 a) s- d" a" B" t0 Q0 V  28 count--;! u2 s9 f/ Y& ~# Z& e6 f
  29 setContext(se);& `8 e4 _# ~) |  C  g
  30 }
2 V* H* @3 N2 X. t" M0 p  31 //设置context的属性,它将激发attributeReplaced或attributeAdded方法
$ {+ H: D6 b. Q$ y  32 public void setContext(HttpSessionEvent se)  t& T0 S1 N1 \7 ?7 [
  33 {
% j4 @0 @/ Q/ x5 Z  34 se.getSession().getServletContext().( C+ p0 n  L5 ?0 e7 I4 {
  setAttribute("onLine",new Integer(count));
3 i' F0 U+ K; L8 i( U: C. B  35 }
' r+ h, S0 f9 ]. C: F3 |) Q& C  36 //增加一个新的属性时激发
4 ?. {, |+ a2 d  37 public void attributeAdded(ServletContextAttributeEvent event) {
, A6 L) [! k6 [# t8 F  38
, ~1 o# H: V9 ]7 q  39 log("attributeAdded('" + event.getName() + "', '" +
8 d: y3 ?( ~( J; F5 v  40 event.getValue() + "')");
& ?# |7 X  n4 n' B1 H  418 |3 P* X* {* X! X4 |
  42 }2 J2 d# B5 s2 Q6 J
  437 w- c: K/ U, a
  44 //删除一个新的属性时激发1 |! U" Z. N2 H4 `5 D% ~! t, P
  45 public void attributeRemoved(ServletContextAttributeEvent event) {) C/ B, Z# V  H. t8 [' `
  462 j1 r* l- T4 H( z
  47 log("attributeRemoved('" + event.getName() + "', '" +
* W2 l( s( C, m3 e$ f0 q  E' q7 z  48 event.getValue() + "')");8 c3 `) b! G% ]$ h! q
  49
) y0 {! W% ?# E/ t+ e4 K  50 }
3 G7 p- l- G! P, x! K& h  51
" j5 q' M5 f; P. F  52 //属性被替代时激发
; Q6 B3 e8 D5 a2 q: L- O6 S  `8 T  53 public void attributeReplaced(ServletContextAttributeEvent event) {
0 t( r) V2 H( h9 y+ C+ a  54
9 p$ H9 {. ]# I# G- C  55 log("attributeReplaced('" + event.getName() + "', '" +) J; r, B$ i$ W- l; ?
  56 event.getValue() + "')");
1 x; r1 w3 m5 A, u6 J# X  57 }
# z! v, H9 L$ Z" F6 Z. l8 c* @7 X  58 //context删除时激发8 G4 U3 u6 v2 @/ Q0 @" R8 D5 l
  59 public void contextDestroyed(ServletContextEvent event) {( u9 @1 s/ x( z
  60
5 G6 y1 s2 d3 U; d  61 log("contextDestroyed()");
1 W1 @7 G* @5 A' t  62 this.context = null;; U5 j+ I) X( v) J2 c
  63: P9 Y) l" L) I" q" D
  64 }. m3 m0 U& B  X7 d9 D3 q5 o  J& l
  65
. {0 R9 k# Z- S% i  k  66 //context初始化时激发
5 v( o5 h- J4 a  67 public void contextInitialized(ServletContextEvent event) {
# ]+ t0 s+ n( [/ W5 y  F  68
: u. m: H/ N! f" _7 c+ L; l  69 this.context = event.getServletContext();
0 G+ G* a4 |8 d. n) c! q, q7 |  70 log("contextInitialized()");# w  Z' `* T% g8 e  f
  71
4 |5 t6 v1 L3 Q% p* @" c  72 }0 T* c+ \( I4 ~- V: W
  73 private void log(String message) {
/ ?- h( T1 q- g) i' {' o! k' O  74
( W6 Y) U/ p3 s# Y8 H8 N( n  75 System.out.println("ContextListener: " + message);- Z4 M& ?: T" \$ Q" V" j
  76 }* x) x' f" z  M  o1 p5 \+ U
  77 }
( S* J) P& \: N  【程序注解】4 ~4 v2 U5 g3 y
  在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的信息是所有客户端共享的,这样,每个客户端都可以读取到当前在线的人数。: D. X0 P: n9 m
  从作用域范围来说,Servlet的作用域有ServletContext,HttpSession,ServletRequest.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-7-31 22:04:28 | 显示全部楼层

2011年计算机等考二级JAVA学习精华整理(71)

  Context范围:; {1 Z5 X' x1 b( D, q+ w
  ServletContextListener:/ H, c4 d1 h" H0 q6 a7 P
  对一个应用进行全局监听.随应用启动而启动,随应用消失而消失主要有两个方法:
. N  k0 F) \' Q+ P" k  contextDestroyed(ServletContextEvent event)) P/ C! Y- Z. _! K
  在应用关闭的时候调用
. W" B8 l# @1 X7 c1 K2 D) O6 L  w. R  contextInitialized(ServletContextEvent event)9 F0 x' x) A8 ^
  在应用启动的时候调用0 D5 h2 N3 U1 x8 s9 ~
  这个监听器主要用于一些随着应用启动而要完成的工作,也就是很多人说的我想在容器4 {3 [, a% y5 u9 {5 u
  启动的时候干..........$ ^+ h, L2 h1 W, m- }, x4 O
  一般来说对"全局变量"初始化,如
: K/ Z# X' {% ~  public void contextInitialized(ServletContextEvent event){: }; B. I( O7 [; R, r  v
  ServletContex sc = event.getServletContext();
4 M4 M. {) L- i6 R  s  sc.setAttribute(name,value);# q! p8 D& ?8 c, Z$ Q- o- s
  }
7 a4 y7 c, Q( d# ]  以后你就可以在任何servlet中getServletContext().getAttribute(name);* f/ w2 ]$ m% }* P
  我最喜欢用它来做守护性工作,就是在contextInitialized(ServletContextEvent event)
5 Q$ z, h5 `5 T, n$ ]4 l1 S  方法中实现一个Timer,然后就让应用在每次启动的时候让这个Timer工作:
7 B7 [- |) Z( C% n" {  程序代码:
9 T' }+ v- O/ C2 L9 }: Z* V  public void contextInitialized(ServletContextEvent event){
2 B1 i7 E) H( A0 i4 q2 E  timer = new Timer();+ G+ e* a* S: d7 o& w- g
  timer.schedule(new TimerTask(){5 S6 k) k2 |* {* b8 l
  public void run(){
3 g$ P# Q. S; ^# c! }4 I  //do any things" B9 x1 H4 ?4 d6 H
  }
: W6 q$ ]* `, M2 F8 P4 Q: R  },0,时间间隔);
; G( Y' b  F0 n5 v: Y3 s  }! i: s7 f0 t  O' P. e: g" u
  有人说Timer只能规定从现在开始的多长时间后,每隔多久做一次事或在什么时间做一次事,那我想在每月1号或每天12点做一项工作如何做呢?你只要设一个间隔,然后每次判断一下当时是不是那个时间段就行了啊,比如每月一号做,那你时间间隔设为天,即24小时一个循环,然后在run方法中判断当时日期new Date().getDate()==1就行了啊.如果是每天的12点,那你时间间隔设为小时,然后在run中判断new Date().getHour()==12,再做某事就行了.0 s! }  X8 u, [! @2 |7 ?
  ServletContextAttributeListener:
  v: |  l0 ~- V0 Z  这个监听器主要监听ServletContex对象在setAttribute()和removeAttribute()的事件,注意,也就是一个"全局变量"在被Add(第一次set),replace(对已有的变量重新赋值)和remove的时候,分别调用下面三个方法:
* J' d* M$ t1 j5 f5 F  public void attributeAdded(ServletContextAttributeEvent scab)这个方法不仅可以知道哪些全局变量被加进来,而且可获取容器在启动时自动设置了哪些context变量:
! g9 S2 P1 Z! \; E& ]- h  程序代码:" V, L3 g* Q' I; n5 F: `5 Y
  public void attributeAdded(ServletContextAttributeEvent scab){
1 Y3 p0 o; }; ~+ u) \% k8 z  System.out.println(scab.getName());& O. }9 L$ d: }5 q2 g9 i; |/ W
  }
7 I1 H3 v! n7 g! Y  public void attributeRemoved(ServletContextAttributeEvent scab)
3 {" l' B$ A$ j6 f( x0 k+ A7 X5 B  public void attributeReplaced(ServletContextAttributeEvent scab): c+ N' }: o1 i6 _/ L2 P% K: y
  Session范围:. b+ Q. T5 \1 ]$ f: z  q
  HttpSessionListener:% W) X, m8 u$ x& \& L$ r) [
  这个监听器主要监听一个Session对象被生成和销毁时发生的事件.对应有两个方法:
# u# _7 n' t% E6 r, g6 D  程序代码:% j( [# h4 ?$ @* k" M; [/ I6 d
  public void sessionCreated(HttpSessionEvent se)3 }! \- f  i$ U$ J- `
  public void sessionDestroyed(HttpSessionEvent se)
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-7-31 22:04:29 | 显示全部楼层

2011年计算机等考二级JAVA学习精华整理(71)

 一般来说,一个session对象被create时,可以说明有一个新客端进入.可以用来粗略统计在线人数,注意这不是精确的,因为这个客户端可能立即就关闭了,但sessionDestroyed方法却会按一定的策略很久以后才会发生.  HttpSessionAttributeListener:和ServletContextAttributeListener一样,它监听一个session对象的Attribut被Add(一个特定名称的Attribute每一次被设置),replace(已有名称的Attribute的值被重设)和remove时的事件.对就的有三个方法.* R3 g2 O0 w1 j" k* }
  程序代码:8 Z/ O/ m2 y" t+ y) W
  public void attributeAdded(HttpSessionBindingEvent se)
9 r2 }  T. v8 ^. I$ [' P  public void attributeRemoved(HttpSessionBindingEvent se)
) R" k1 Y- h/ i+ a9 m- b4 _  public void attributeReplaced(HttpSessionBindingEvent se)* u" }6 V( J9 G% O3 k
  上面的几个监听器的方法,都是在监听应用逻辑中servlet逻辑中发生了什么事,一般的来说.我们只要完成逻辑功能,比如session.setAttribute("aaa","111");我只要把一个名为aaa的变量放在session中以便以后我能获取它,我并不关心当session.setAttribute("aaa","111");发生时我还要干什么.(当然有些时候要利用的),但对于下面这个监听器,你应该好好发解一下:
5 W' i$ ~  a  Z- F3 P( v/ t  HttpSessionBindingListener:% ~0 Y  g2 b" c: x8 b9 B6 ]
  上面的监听器都是作为一个独立的Listener在容器中控制事件的.而HttpSessionBindingListener对在一对象中监听该对象的状态,实现了该接口的对象如果被作为value被add到一个session中或从session中remove,它就会知道自己已经作为一个session对象或已经从session删除,这对于一些非纯JAVA对象,生命周期长于session的对象,以及其它需要释放资源或改变状态的对象非常重要.8 M% U; U2 M# n
  比如:5 \0 H* b3 L  P' E, s8 d
  session.setAttribute("abcd","1111");
" _; a& t$ f3 F# _- a6 d  以后session.removeAttribute("abcd");因为abcd是一个字符中,你从session中remove后,它就会自动被垃圾回收器回收,而如果是一个connection:(只是举例,你千万不要加connection往session中加入)+ u2 c/ m4 q$ i" z1 G9 @7 g; ^
  程序代码:* E  x- L' g) o2 u4 v
  session.setAttribute("abcd",conn);9 T( r2 j% `4 h1 g) V/ ^- s
  以后session.removeAttribute("abcd");这时这个conn被从session中remove了,你已经无法获取它的句柄,所以你根本没法关闭它.而在没有remove之前你根本不知道什么时候要被remove,你又无法close(),那么这个connection对象就死了.另外还有一些对象可以在被加入一个session时要锁定还要被remove时要解锁,应因你在程序中无法判断什么时候被remove(),add还好操作,我可以先加锁再add,但remove就后你就找不到它的句柄了,根本没法解锁,所以这些操作只能在对象自身中实现.也就是在对象被add时或remove时通知对象自己回调相应的方法:5 L2 T8 Z2 y3 e: s
  程序代码:9 ~6 ]0 `# K9 r, z9 e
  MyConn extends Connection implements HttpSessionBindingListener{
' h# Q. h1 q; r7 q! B  public void valueBound(HttpSessionBindingEvent se){
8 }* f9 E8 @: s3 B  this.initXXX();! e' J, n0 r' n, d  ~! v1 g
  }' O: a# U1 Z9 Q8 |5 x8 l! G
  public void valueUnbound(HttpSessionBindingEvent se){
8 v3 _7 |0 F, a$ u- r  this.close();
! v( m  o5 S% y* Y/ T( f  }0 T6 |9 ?& @! R' F2 _
  }
  w  n) e1 y# l/ U/ F+ g  session.setAttribute("aaa",new MyConn());* L! K6 J) n2 a) j6 Y0 X- Q: \) m; J
  这时如果调用session.removeAttribute("aaa"),则触发valueUnbound方法,就会自动关闭自己.而其它的需要改变状态的对象了是一样.
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-5-3 00:07 , Processed in 0.220997 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表