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

一、统计当前在线人数

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

package me.gacl.web.listener;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener; /**
* @ClassName: OnLineCountListener
* @Description: 统计当前在线用户个数
* @author: 孤傲苍狼
* @date: 2014-9-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 me.gacl.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: 孤傲苍狼
* @date: 2014-9-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: 孤傲苍狼
* @date: 2014-9-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();
}
}
}
}
}

javaWeb学习总结(11)- 监听器(Listener)在开发中的应用的更多相关文章

  1. JavaWeb学习 (二十七)————监听器(Listener)在开发中的应用

    监听器在JavaWeb开发中用得比较多,下面说一下监听器(Listener)在开发中的常见应用 一.统计当前在线人数 在JavaWeb应用开发中,有时候我们需要统计当前在线的用户数,此时就可以使用监听 ...

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

    监听器在JavaWeb开发中用得比较多,下面说一下监听器(Listener)在开发中的常见应用 一.统计当前在线人数 在JavaWeb应用开发中,有时候我们需要统计当前在线的用户数,此时就可以使用监听 ...

  3. javaweb学习总结二十二(servlet开发中常见的问题汇总)

    一:web应用的映射问题 通常我们从别人那里拷贝来的代码,自己会修改应用的名称,但是web映射的访问路径并没有修改,还是原来的映射. 解决方法: 工程右键--properties--myeclipse ...

  4. javaweb学习总结(四十三)——Filter高级开发

    在filter中可以得到代表用户请求和响应的request.response对象,因此在编程中可以使用Decorator(装饰器)模式对request.response对象进行包装,再把包装对象传给目 ...

  5. JavaWeb学习笔记八 监听器

    监听器Listener jservlet规范包括三个技术点:servlet :listener :filter:监听器就是监听某个对象的的状态变化的组件.监听器的相关概念事件源: 被监听的对象(三个域 ...

  6. ios学习笔记之block在ios开发中的应用

    一.什么是Blocks      Block是一个C级别的语法以及运行时的一个特性,和标准C中的函数(函数指针)类似,但是其运行需要编译器和运行时支持,从ios4.0开始就很好的支持Block. 二. ...

  7. JavaWeb学习总结第四篇--Servlet开发

    Servlet开发 用户在浏览器中输入一个网址并回车,浏览器会向服务器发送一个HTTP请求.服务器端程序接受这个请求,并对请求进行处理,然后发送一个回应.浏览器收到回应,再把回应的内容显示出来.这种请 ...

  8. javaWeb学习之运用myeclipse结合tomcat开发一些简单的jsp和service

    servlet是什么?     servlet是java服务器端编程.不同于我们之前写的一般的java应用程序,Servlet程序是运行在服务器上的,服务器有很多种.....现在只是用过 tomcat ...

  9. JavaWeb学习记录(十九)——开发JSTL自定义标签

    一.防盗链标签 import javax.servlet.http.HttpServletResponse;import javax.servlet.jsp.JspException;import j ...

随机推荐

  1. React-Native 之 项目实战(四)

    前言 本文有配套视频,可以酌情观看. 文中内容因各人理解不同,可能会有所偏差,欢迎朋友们联系我. 文中所有内容仅供学习交流之用,不可用于商业用途,如因此引起的相关法律法规责任,与我无关. 如文中内容对 ...

  2. C++命名空间的解释 【转】

    使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突.在C++中,变量.函数和类都是大量存在的.如果没有命名空间,这些变量.函数.类的名称将都存在于全局命名空间中,会导致很多冲突.比如,如果我 ...

  3. C#中的DateTime是值类型还是引用类型

    近期遇到了DateTime到底是值类型还是引用类型的疑惑,顺势较深入地了解一下DateTime相关的内容 结论:DateTime是值类型,因为DateTime是结构体,而结构体继承自Syste.Val ...

  4. 服务器上的Git

    前面的话 如果想与他人使用,除了使用Git来完成日常工作之外,还需要一个远程的Git仓库.尽管从技术上可以从个人的仓库里推送和拉取修改内容,但并不鼓励这样做,因为一不留心就很容易弄混其他人的进度.因此 ...

  5. DOM Mutation Observer

    源链接:http://www.jianshu.com/p/b5c9e4c7b1e1

  6. linux sed命令就是这么简单

    概述 sed命令是一个面向字符流的非交互式编辑器,也就是说sed不允许用户与它进行交互操作.sed是按行来处理文本内容的.在shell中,使用sed来批量修改文本内容是非常方便的. sed命令的选项 ...

  7. 为什么不能将客户端的连接请求跳转或转发到本机lo回环接口上?

    一.为什么不能将本机的请求跳转/转发到回环接口上? 如上图一样,服务器对外只开放了一个80端口,但是web服务监听在了lo 接口上8080端口上,现在要实现外网通过访问服务器的80端口,来提供web服 ...

  8. struts2 之 ServletAPI

    1. 在struts2中有两种方式使用SercletAPI,一种解耦方式,一种耦合方式. 2. 解耦方式就是使用ActionContext 来实现,是完全解耦 servletAPI. ActionCo ...

  9. 告别findViewById(),ButterKnife,使用Google Data Binding Library(1)

    Data Binding Library 用数据绑定编写声名性布局,可以最大限度的减少findViewById(),setOnClickListener()之类的代码.并且比起findViewById ...

  10. linux C/C++ 日志打印函数

    //宏定义日志文件名 #define PROCESSNAME  "log_filename" //当日志文件大于5M时,会删除该文件,该接口使用方法 参照printfvoid Wr ...