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

  统计当前在线人数

  自定义Session扫描器

一、统计当前在线人数

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

package com.web.listener;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener; /**
* @ClassName: OnLineCountListener
* @Description: 统计当前在线用户个数
* @author: hdb
* @date: 2017-12-10 10:01:26
*
*/
public class OnLineCountListener implements HttpSessionListener { @Override
public void sessionCreated(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);
}
} @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扫描器

  当一个Web应用创建的Session很多时,为了避免Session占用太多的内存,我们可以选择手动将这些内存中的session销毁,那么此时也可以借助监听器技术来实现。

package com.web.listener;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Timer;
import java.util.TimerTask;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener; /**
* @ClassName: SessionScanerListener
* @Description: 自定义session扫描器
* @author: hdb
* @date: 2017-12-10 10:16:42
*
*/
public class SessionScanerListener implements HttpSessionListener,ServletContextListener { /**
* @Field: list
* 定义一个集合存储服务器创建的HttpSession
* LinkedList不是一个线程安全的集合
*/
/**
* private List<HttpSession> list = new LinkedList<HttpSession>();
* 这样写涉及到线程安全问题,SessionScanerListener对象在内存中只有一个
* sessionCreated可能会被多个人同时调用,
* 当有多个人并发访问站点时,服务器同时为这些并发访问的人创建session
* 那么sessionCreated方法在某一时刻内会被几个线程同时调用,几个线程并发调用sessionCreated方法
* sessionCreated方法的内部处理是往一个集合中添加创建好的session,那么在加session的时候就会
* 涉及到几个Session同时抢夺集合中一个位置的情况,所以往集合中添加session时,一定要保证集合是线程安全的才行
* 如何把一个集合做成线程安全的集合呢?
* 可以使用使用 Collections.synchronizedList(List<T> list)方法将不是线程安全的list集合包装线程安全的list集合
*/
//使用 Collections.synchronizedList(List<T> list)方法将LinkedList包装成一个线程安全的集合
private List<HttpSession> list = Collections.synchronizedList(new LinkedList<HttpSession>());
//定义一个对象,让这个对象充当一把锁,用这把锁来保证往list集合添加的新的session和遍历list集合中的session这两个操作达到同步
private Object lock = new Object(); @Override
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);
}
} @Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("session被销毁了了!!");
} /* Web应用启动时触发这个事件
* @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("web应用初始化");
//创建定时器
Timer timer = new Timer();
//每隔30秒就定时执行任务
timer.schedule(new MyTask(list,lock), 0, 1000*30);
} @Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("web应用关闭");
}
} /**
* @ClassName: MyTask
* @Description:定时器要定时执行的任务
* @author: hdb
* @date: 2017-12-11 12:02:36
*
*/
class MyTask extends TimerTask { //存储HttpSession的list集合
private List<HttpSession> list;
//存储传递过来的锁
private Object lock;
public MyTask(List<HttpSession> list,Object lock){
this.list = list;
this.lock = lock;
}
/* run方法指明了任务要做的事情
* @see java.util.TimerTask#run()
*/
@Override
public void run() {
//将该操作加锁进行锁定
synchronized (lock) {
System.out.println("定时器执行!!");
ListIterator<HttpSession> it = list.listIterator();
/**
* 迭代list集合中的session,在迭代list集合中的session的过程中可能有别的用户来访问,
* 用户一访问,服务器就会为该用户创建一个session,此时就会调用sessionCreated往list集合中添加新的session,
* 然而定时器在定时执行扫描遍历list集合中的session时是无法知道正在遍历的list集合又添加的新的session进来了,
* 这样就导致了往list集合添加的新的session和遍历list集合中的session这两个操作无法达到同步
* 那么解决的办法就是把"list.add(session)和while(it.hasNext()){//迭代list集合}"这两段代码做成同步,
* 保证当有一个线程在访问"list.add(session)"这段代码时,另一个线程就不能访问"while(it.hasNext()){//迭代list集合}"这段代码
* 为了能够将这两段不相干的代码做成同步,只能定义一把锁(Object lock),然后给这两步操作加上同一把锁,
* 用这把锁来保证往list集合添加的新的session和遍历list集合中的session这两个操作达到同步
* 当在执行往list集合添加的新的session操作时,就必须等添加完成之后才能够对list集合进行迭代操作,
* 当在执行对list集合进行迭代操作时,那么必须等到迭代操作结束之后才能够往往list集合添加的新的session
*/
while(it.hasNext()){
HttpSession session = (HttpSession) it.next();
/**
* 如果当前时间-session的最后访问时间>1000*15(15秒)
* session.getLastAccessedTime()获取session的最后访问时间
*/
if(System.currentTimeMillis()-session.getLastAccessedTime()>1000*30){
//手动销毁session
session.invalidate();
//移除集合中已经被销毁的session
it.remove();
}
}
}
}
}

监听器(Listener)学习(二)在开发中的常见应用的更多相关文章

  1. javaweb学习总结(四十五)——监听器(Listener)学习二

    一.监听域对象中属性的变更的监听器 域对象中属性的变更的事件监听器就是用来监听 ServletContext, HttpSession, HttpServletRequest 这三个对象中的属性变更信 ...

  2. JavaWeb学习 (二十六)————监听器(Listener)学习(二)

    一.监听域对象中属性的变更的监听器 域对象中属性的变更的事件监听器就是用来监听 ServletContext, HttpSession, HttpServletRequest 这三个对象中的属性变更信 ...

  3. CAD二次开发中浮动面板不浮动的问题

    CAD二次开发中创建了一个浮动面板,想让它创建出来后以浮动状态显示, 但是DockSides.None设置完后,面板还是不浮动.搞了很久,最后原来是 需要先设置Visible,再设置DockSides ...

  4. Android开发中一些常见的问题解决方案

    分享一下自己开发中遇到的一些常见问题及解决方案,方面以后快速开发少走弯路,也可以供大家一起学习. 1.开发中很常见的一个问题,项目中的listview不仅仅是简单的文字,常常需要自己定义listvie ...

  5. 5个Android开发中比较常见的内存泄漏问题及解决办法

    android中一个对象已经不需要了,但是其他对象还持有他的引用,导致他不能回收,导致这个对象暂存在内存中,这样内存泄漏就出现了.   内存泄漏出现多了,会是应用占用过多的没存,当占用的内存超过了系统 ...

  6. 团队项目开发中,常见的版本控制有svn,git

    团队项目开发中,常见的版本控制有svn,git

  7. 游戏开发中IIS常见支持MIME类型文件解析

    游戏开发中IIS常见支持MIME类型文件解析 .apkapplication/vnd.android .ipaapplication/vnd.iphone .csbapplication/octet- ...

  8. WEB开发中一些常见的攻击方式及简单的防御方法

    WEB开发中一些常见的攻击方式及简单的防御方法 转载:http://blog.csdn.net/seven__________7/article/details/70896913

  9. 监听器(Listener)学习(二)

    一.监听域对象中属性的变更的监听器 域对象中属性的变更的事件监听器就是用来监听 ServletContext, HttpSession, HttpServletRequest 这三个对象中的属性变更信 ...

随机推荐

  1. Mac 终端命令行报错 -bash: vi: command not found

    我遇到的问题与这个类似,但是我的问题也是用该博文作者方法进行中断才解决的,在此表示感谢. 前段时间在 Mac 下使用终端遇到了这个问题: appledeMacBook-Air:~ air$ vi .b ...

  2. linux定时任务php

    1. 在需要定时执行的PHP文件的第一行加 #! /usr/local/php/bin/php          服务器php.exe的位置 2. 上传要定时执行的php文件到一个位置,可以通过/pa ...

  3. 可能是最好的 Rx 初学者教程

    译文:https://zhuanlan.zhihu.com/p/25552305 原文:https://gist.github.com/staltz/868e7e9bc2a7b8c1f754

  4. [转]通过rsync+inotify-tools+ssh实现触发式远程实时同步

    文件的同步镜像在很多地方都需要用到,因此rsync这款免费软件得到了广泛的应用,包括在Windows平台上,都已经有了支持rsync的“cwRsyncServer”. 但是,我们一般都是通过结合cro ...

  5. 为cloudstack搭建ceph文件系统

    1. 安装dell服务器,  raid卡需要采用直通模式(non-raid); 各磁盘独立运行.  网络依赖硬件不同,使用万兆网卡或者两个千兆网卡做bonding6.  2. 配置host map(1 ...

  6. Java MongoDB插入

    前言 插入是向MongoDB中添加数据的基本方法.对目标集使用insert方法来插入一条文档.这个方法会给文档增加一个”_id”属性(如果原来没有的话),然后保存到数据库中. 1.连接数据库,拿到集合 ...

  7. 极小极大搜索 的个人理解(alpha-beta剪枝)

    极小极大搜索的算法过程: 参考文档:http://www.xqbase.com/computer/search_minimax.htm (经典) 主要思想比较简单,但说清楚也不大容易.其核心思想是通过 ...

  8. Putty实现Linux与Windows互传文件

    putty远程连接VPS,先开一贴,有空来整理. 从putty官网下载putty,选择[A Windows installer for everything except PuTTYtel]安装包,下 ...

  9. 华为EPON OLT开局配置

      配置思路: 1. 登录olt(console进去之后配地址) 2.配置上联口(配vlan和起三层地址互联路由的lan口) 3.epon接分光器,分光器下接光猫 4.自动发现光猫.配置DBA数据和线 ...

  10. 转:聊聊Greenplum的那些事

    笔者有幸从04年就开始从事大规模数据计算的相关工作,08年作为Greenplum 早期员工加入Greenplum团队(当时的工牌是“005”,哈哈),记得当时看了一眼Greenplum的架构(嗯,就是 ...