javaWeb学习总结(11)- 监听器(Listener)在开发中的应用

监听器在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();
                }
            }
        }
    }
}
时间: 2024-10-20 01:02:06

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

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

监听器在JavaWeb开发中用得比较多,下面说一下监听器(Listener)在开发中的常见应用 一.统计当前在线人数 在JavaWeb应用开发中,有时候我们需要统计当前在线的用户数,此时就可以使用监听器技术来实现这个功能了. 1 package me.gacl.web.listener; 2 3 import javax.servlet.ServletContext; 4 import javax.servlet.http.HttpSessionEvent; 5 import javax.ser

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

监听器在JavaWeb开发中用得比较多,下面说一下监听器(Listener)在开发中的常见应用 一.统计当前在线人数 在JavaWeb应用开发中,有时候我们需要统计当前在线的用户数,此时就可以使用监听器技术来实现这个功能了. 1 package me.gacl.web.listener; 2 3 import javax.servlet.ServletContext; 4 import javax.servlet.http.HttpSessionEvent; 5 import javax.ser

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

一:web应用的映射问题 通常我们从别人那里拷贝来的代码,自己会修改应用的名称,但是web映射的访问路径并没有修改,还是原来的映射. 解决方法: 工程右键--properties--myeclipse--web,修改webroot即可 二:web.xml配置文件 web.xml中的配置文件信息如下: 三:同一个servlet类可以映射到多个url地址上  

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

servlet是什么?     servlet是java服务器端编程.不同于我们之前写的一般的java应用程序,Servlet程序是运行在服务器上的,服务器有很多种.....现在只是用过 tomcat.....哇咔咔     )—— 最大的特点是没有类方法....    )—— javaWeb学习之运用myeclipse结合tomcat开发一些简单的jsp和service

javaweb学习总结——基于Servlet+JSP+JavaBean开发模式的用户登录注册

一.Servlet+JSP+JavaBean开发模式(MVC)介绍 Servlet+JSP+JavaBean模式(MVC)适合开发复杂的web应用,在这种模式下,servlet负责处理用户请求,jsp负责数据显示,javabean负责封装数据. Servlet+JSP+JavaBean模式程序各个模块之间层次清晰,web开发推荐采用此种模式. 这里以一个最常用的用户登录注册程序来讲解Servlet+JSP+JavaBean开发模式,通过这个用户登录注册程序综合案例,把之前的学过的XML.Xpat

JavaWeb学习总结(基于Servlet+JSP+JavaBean开发模式的用户登录注册)

一.Servlet+JSP+JavaBean开发模式(MVC)介绍 Servlet+JSP+JavaBean模式(MVC)适合开发复杂的web应用,在这种模式下,servlet负责处理用户请求,jsp负责数据显示,javabean负责封装数据. Servlet+JSP+JavaBean模式程序各个模块之间层次清晰,web开发推荐采用此种模式. 这里以一个最常用的用户登录注册程序来讲解Servlet+JSP+JavaBean开发模式,通过这个用户登录注册程序综合案例,把之前的学过的XML.Xpat

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

在filter中可以得到代表用户请求和响应的request.response对象,因此在编程中可以使用Decorator(装饰器)模式对request.response对象进行包装,再把包装对象传给目标资源,从而实现一些特殊需求. 一.Decorator设计模式 1.1.Decorator设计模式介绍 当某个对象的方法不适应业务需求时,通常有2种方式可以对方法进行增强: 编写子类,覆盖需增强的方法. 使用Decorator设计模式对方法进行增强. 在阎宏博士的<JAVA与模式>一书中开头是这样

JavaWeb学习笔记八 监听器

监听器Listener jservlet规范包括三个技术点:servlet :listener :filter:监听器就是监听某个对象的的状态变化的组件.监听器的相关概念事件源: 被监听的对象(三个域对象 request,session,servletContext) 监听器:监听事件源对象, 事件源对象的状态的变化都会触发监听器 . 注册监听器:将监听器与事件源进行绑定. 响应行为:监听器监听到事件源的状态变化时,所涉及的功能代码(程序员编写代码) 按照被监听的对象划分:ServletRequ

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

一.什么是Blocks      Block是一个C级别的语法以及运行时的一个特性,和标准C中的函数(函数指针)类似,但是其运行需要编译器和运行时支持,从ios4.0开始就很好的支持Block. 二.在ios开发中,什么情况下使用Block      Block除了能够定义参数列表.返回类型外,还能够获取被定义时的词法范围内的状态(比如局部变量),并且在一定条件下(比如使用__block变量)能够修改这些状态.此外,这些可修改的状态在相同词法范围内的多个block之间是共享的,即便出了该词法范围