转载:javaweb学习总结(四十七)——监听器(Listener)在开发中的应用

javaweb学习总结(四十七)——监听器(Listener)在开发中的应用

转自:http://www.cnblogs.com/xdp-gacl/p/3965508.htmlhtml

  监听器在JavaWeb开发中用得比较多,下面说一下监听器(Listener)在开发中的常见应用前端

1、统计当前在线人数

  在JavaWeb应用开发中,有时候咱们须要统计当前在线的用户数,此时就可使用监听器技术来实现这个功能了。java

复制代码
 1 package me.gacl.web.listener;  2  3 import javax.servlet.ServletContext;  4 import javax.servlet.http.HttpSessionEvent;  5 import javax.servlet.http.HttpSessionListener;  6  7 /**  8 * @ClassName: OnLineCountListener  9 * @Description: 统计当前在线用户个数 10 * @author: 孤傲苍狼 11 * @date: 2014-9-10 下午10:01:26 12 * 13 */ 14 public class OnLineCountListener implements HttpSessionListener { 15 16  @Override 17 public void sessionCreated(HttpSessionEvent se) { 18 ServletContext context = se.getSession().getServletContext(); 19 Integer onLineCount = (Integer) context.getAttribute("onLineCount"); 20 if(onLineCount==null){ 21 context.setAttribute("onLineCount", 1); 22 }else{ 23 onLineCount++; 24 context.setAttribute("onLineCount", onLineCount); 25  } 26  } 27 28  @Override 29 public void sessionDestroyed(HttpSessionEvent se) { 30 ServletContext context = se.getSession().getServletContext(); 31 Integer onLineCount = (Integer) context.getAttribute("onLineCount"); 32 if(onLineCount==null){ 33 context.setAttribute("onLineCount", 1); 34 }else{ 35 onLineCount--; 36 context.setAttribute("onLineCount", onLineCount); 37  } 38  } 39 }
复制代码

2、自定义Session扫描器

  当一个Web应用建立的Session不少时,为了不Session占用太多的内存,咱们能够选择手动将这些内存中的session销毁,那么此时也能够借助监听器技术来实现。git

复制代码
  1 package me.gacl.web.listener;  2  3 import java.util.Collections;  4 import java.util.LinkedList;  5 import java.util.List;  6 import java.util.ListIterator;  7 import java.util.Timer;  8 import java.util.TimerTask;  9 import javax.servlet.ServletContextEvent;  10 import javax.servlet.ServletContextListener;  11 import javax.servlet.http.HttpSession;  12 import javax.servlet.http.HttpSessionEvent;  13 import javax.servlet.http.HttpSessionListener;  14  15 /**  16 * @ClassName: SessionScanerListener  17 * @Description: 自定义session扫描器  18 * @author: 孤傲苍狼  19 * @date: 2014-9-10 下午10:16:42  20 *  21 */  22 public class SessionScanerListener implements HttpSessionListener,ServletContextListener {  23  24 /**  25  * @Field: list  26  * 定义一个集合存储服务器建立的HttpSession  27  * LinkedList不是一个线程安全的集合  28 */  29 /**  30  * private List<HttpSession> list = new LinkedList<HttpSession>();  31  * 这样写涉及到线程安全问题,SessionScanerListener对象在内存中只有一个  32  * sessionCreated可能会被多我的同时调用,  33  * 当有多我的并发访问站点时,服务器同时为这些并发访问的人建立session  34  * 那么sessionCreated方法在某一时刻内会被几个线程同时调用,几个线程并发调用sessionCreated方法  35  * sessionCreated方法的内部处理是往一个集合中添加建立好的session,那么在加session的时候就会  36  * 涉及到几个Session同时抢夺集合中一个位置的状况,因此往集合中添加session时,必定要保证集合是线程安全的才行  37  * 如何把一个集合作成线程安全的集合呢?  38  * 可使用使用 Collections.synchronizedList(List<T> list)方法将不是线程安全的list集合包装线程安全的list集合  39 */  40 //使用 Collections.synchronizedList(List<T> list)方法将LinkedList包装成一个线程安全的集合  41 private List<HttpSession> list = Collections.synchronizedList(new LinkedList<HttpSession>());  42 //定义一个对象,让这个对象充当一把锁,用这把锁来保证往list集合添加的新的session和遍历list集合中的session这两个操做达到同步  43 private Object lock = new Object();  44  45  @Override  46 public void sessionCreated(HttpSessionEvent se) {  47 System.out.println("session被建立了!!");  48 HttpSession session = se.getSession();  49  50 synchronized (lock){  51 /**  52  *将该操做加锁进行锁定,当有一个thread-1(线程1)在调用这段代码时,会先拿到lock这把锁,而后往集合中添加session,  53  *在添加session的这个过程当中假设有另一个thread-2(线程2)来访问了,thread-2多是执行定时器任务的,  54  *当thread-2要调用run方法遍历list集合中的session时,结果发现遍历list集合中的session的那段代码被锁住了,  55  *而这把锁正在被往集合中添加session的那个thread-1占用着,所以thread-2只能等待thread-1操做完成以后才可以进行操做  56  *当thread-1添加完session以后,就把lock放开了,此时thread-2拿到lock,就能够执行遍历list集合中的session的那段代码了  57  *经过这把锁就保证了往集合中添加session和变量集合中的session这两步操做不能同时进行,必须按照先来后到的顺序来进行。  58 */  59  list.add(session);  60  }  61  }  62  63  @Override  64 public void sessionDestroyed(HttpSessionEvent se) {  65 System.out.println("session被销毁了了!!");  66  }  67  68 /* Web应用启动时触发这个事件  69  * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)  70 */  71  @Override  72 public void contextInitialized(ServletContextEvent sce) {  73 System.out.println("web应用初始化");  74 //建立定时器  75 Timer timer = new Timer();  76 //每隔30秒就定时执行任务  77 timer.schedule(new MyTask(list,lock), 0, 1000*30);  78  }  79  80  @Override  81 public void contextDestroyed(ServletContextEvent sce) {  82 System.out.println("web应用关闭");  83 } 84 } 85 86 /** 87 * @ClassName: MyTask 88 * @Description:定时器要定时执行的任务 89 * @author: 孤傲苍狼 90 * @date: 2014-9-11 上午12:02:36 91 * 92 */ 93 class MyTask extends TimerTask { 94 95 //存储HttpSession的list集合 96 private List<HttpSession> list; 97 //存储传递过来的锁 98 private Object lock; 99 public MyTask(List<HttpSession> list,Object lock){ 100 this.list = list; 101 this.lock = lock; 102 } 103 /* run方法指明了任务要作的事情 104 * @see java.util.TimerTask#run() 105 */ 106 @Override 107 public void run() { 108 //将该操做加锁进行锁定 109 synchronized (lock) { 110 System.out.println("定时器执行!!"); 111 ListIterator<HttpSession> it = list.listIterator(); 112 /** 113 * 迭代list集合中的session,在迭代list集合中的session的过程当中可能有别的用户来访问, 114 * 用户一访问,服务器就会为该用户建立一个session,此时就会调用sessionCreated往list集合中添加新的session, 115 * 然而定时器在定时执行扫描遍历list集合中的session时是没法知道正在遍历的list集合又添加的新的session进来了, 116 * 这样就致使了往list集合添加的新的session和遍历list集合中的session这两个操做没法达到同步 117 * 那么解决的办法就是把"list.add(session)和while(it.hasNext()){//迭代list集合}"这两段代码作成同步, 118 * 保证当有一个线程在访问"list.add(session)"这段代码时,另外一个线程就不能访问"while(it.hasNext()){//迭代list集合}"这段代码 119 * 为了可以将这两段不相干的代码作成同步,只能定义一把锁(Object lock),而后给这两步操做加上同一把锁, 120 * 用这把锁来保证往list集合添加的新的session和遍历list集合中的session这两个操做达到同步 121 * 当在执行往list集合添加的新的session操做时,就必须等添加完成以后才可以对list集合进行迭代操做, 122 * 当在执行对list集合进行迭代操做时,那么必须等到迭代操做结束以后才可以每每list集合添加的新的session 123 */ 124 while(it.hasNext()){ 125 HttpSession session = (HttpSession) it.next(); 126 /** 127 * 若是当前时间-session的最后访问时间>1000*15(15秒) 128 * session.getLastAccessedTime()获取session的最后访问时间 129 */ 130 if(System.currentTimeMillis()-session.getLastAccessedTime()>1000*30){ 131 //手动销毁session 132 session.invalidate(); 133 //移除集合中已经被销毁的session 134 it.remove(); 135 } 136 } 137 } 138 } 139 }
复制代码

 以上就是监听器的两个简单应用场景。web

好文要顶 已关注 收藏该文
5
0
 
« 上一篇: WebService学习总结(一)——WebService的相关概念
» 下一篇: JavaWeb学习总结(四十八)——模拟Servlet3.0使用注解的方式配置Servlet

posted on 2014-11-16 12:35 孤傲苍狼 阅读(25090) 评论(5) 编辑 收藏安全

评论

#1楼 2015-01-09 09:38 友人M  

 

     
 
1
2
3
4
5
6
7
8
9
10
11
@Override
     public void sessionDestroyed(HttpSessionEvent se) {
         ServletContext context = se.getSession().getServletContext();
         Integer onLineCount = (Integer) context.getAttribute( "onLineCount" );
         if (onLineCount== null ){
             context.setAttribute( "onLineCount" , 1 );
         } else {
             onLineCount--;
             context.setAttribute( "onLineCount" , onLineCount);
         }
     }

统计在线人数的代码里面:
销毁的Session域里面的用户时,这里的代码有这样一段,
if(onLineCount == null)
{
context.setAttribute("onLineCount",1);
}
超出个人理解范围了。
(并且这个代码,单线程还好,共享变量没有进行同步处理,可能要出问题)
(好吧、后面就加锁了)
后面一段代码中:

if(System.currentTimeMillis()-session.getLastAccessedTime()>1000*30){
//手动销毁session
session.invalidate();
//移除集合中已经被销毁的session
it.remove();
}
以为能够调换一下顺序:
//移除集合中已经被销毁的session
it.remove();
//手动销毁session
session.invalidate();
 
     

  回复引用服务器

#2楼 2015-06-03 13:52 山川尽美  

 

     
 

@ 友人M
以为能够调换一下顺序:
//移除集合中已经被销毁的session
it.remove();
//手动销毁session
session.invalidate();

这里不能够调换微信

 
     

  回复引用session

#3楼 2015-12-18 14:59 weidi  

 

     
 

online是个单词,是否是应该换成Online并发

 
     

  回复引用

#4楼 2016-12-03 00:57 PengWenHao  

 

     
 

怎么只有后台代码,没有前端代码呢?

 
     

  回复引用

#5楼 2016-12-19 10:14 轻吻指尖  

 

     
 

有个问题没想明白:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void sessionCreated(HttpSessionEvent se) {
         System.out.println( "session被建立了!!" );
         HttpSession session = se.getSession();
         
         synchronized (lock){
             /**
              *将该操做加锁进行锁定,当有一个thread-1(线程1)在调用这段代码时,会先拿到lock这把锁,而后往集合中添加session,
              *在添加session的这个过程当中假设有另一个thread-2(线程2)来访问了,thread-2多是执行定时器任务的,
              *当thread-2要调用run方法遍历list集合中的session时,结果发现遍历list集合中的session的那段代码被锁住了,
              *而这把锁正在被往集合中添加session的那个thread-1占用着,所以thread-2只能等待thread-1操做完成以后才可以进行操做
              *当thread-1添加完session以后,就把lock放开了,此时thread-2拿到lock,就能够执行遍历list集合中的session的那段代码了
              *经过这把锁就保证了往集合中添加session和变量集合中的session这两步操做不能同时进行,必须按照先来后到的顺序来进行。
              */
             list.add(session);
         }
向集合中添加session的操做已经加锁了,那么集合自己还须要线程安全吗?
相关文章
相关标签/搜索