• Java Web(五) 监听器Listener


    监听器概述

    在上一篇里介绍了过滤器Filter,而Listener是Servlet的另一个高级特性。Listener用于监听Java Web程序中的事件,例如创建,修改,删除Session,request,context等,并触发相应的事件。Listener主要用于对Session,request,context等进行监控,目前共有8种Listener,分别完成对不同事件的监听。

    使用Listener不需要关注事件是怎样触发的或者怎么调用相应的Listener,只要记住该类事件触发时一定会调用相应的Listener。你只需要在Lisener里编写相关的代码就可以。

    Servlet3.0以前需要在web.xml中配置,之后直接用@WebListener()注解即可。

    <listener>
      <listener-class>listener.TestListener</listener-class>
    </listener>
    

    监听对象的创建与销毁

    HttpSessionListener,ServletContextListener,ServletRequestListener分别用来监控Session,context,request的创建于销毁。触发时机为:

    • HttpSessionListener:创建Session时执行sessionCreatedf方法,超时或者执行session.invalidate()时执行sessionDestroy方法。该Listener可用于收集在线者信息。
    • ServletContextListener:服务器启动或者热部署war包时执行contextInitialized方法。服务器关闭时执行contextDestroyed方法。该Listener可用于启动时获取web.xml里配置的初始化参数。
    • ServletRequest:用户每次请求时都会执行requestInitialized方法。request处理完毕自动销毁前执行requestDestroyed方法。

    实例:因为java可以继承多个接口,所以用一个类继承这三个接口即可。

    package listener; 
    
    /**
     * Created by kindleheart happily.
     */
    import javax.servlet.*;
    import javax.servlet.annotation.WebListener;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    
    @WebListener
    public class TestListener implements ServletContextListener, HttpSessionListener, ServletRequestListener {
        public TestListener() {
        }
    
        //加载context上下文时被调用
        public void contextInitialized(ServletContextEvent sce) {
            ServletContext servletContext = sce.getServletContext();
            System.out.println("即将启动" + servletContext.getContextPath());
        }
        //销毁context上下文时被调用
        public void contextDestroyed(ServletContextEvent sce) {
            ServletContext servletContext = sce.getServletContext();
            System.out.println("即将关闭" + servletContext.getContextPath());
        }
        //创建Session时被调用
        public void sessionCreated(HttpSessionEvent se) {
            HttpSession session = se.getSession();
            System.out.println("新创建一个Session,ID为:" + session.getId());
        }
        //销毁Session时被调用
        public void sessionDestroyed(HttpSessionEvent se) {
            HttpSession session = se.getSession();
            System.out.println("销毁一个Session,ID为:" + session.getId());
        }
        //创建request时被调用
        public void requestInitialized(ServletRequestEvent sre) {
            //存储创建request时的时间
            HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
            request.setAttribute("dateCrated", System.currentTimeMillis());
        }
        //销毁request时被调用
        public void requestDestroyed(ServletRequestEvent sre) {
            //计算该请求所需时间
            HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
            long time = System.currentTimeMillis() - (Long)request.getAttribute("dateCrated");
            System.out.println("请求处理结束,用时" + time + "毫秒");
        }
    
    }
    

    监听对象属性的变化

    HttpSessionAttributeListener,ServletContextAttributeListener,ServletRequestAttributeListener分别用来监控Session,context,request的属性变化。在向监听对象添加,更新,移除属性时,会分别执行xxxAdded(),xxxReplaced(),xxxRemoved()方法,xxx分别代表Session,context,request。

    /**
     * Created by kindleheart happily.
     */
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.annotation.WebListener;
    import javax.servlet.http.*;
    
    @WebListener
    public class SessionAttributeListenerTest implements HttpSessionAttributeListener {
        public SessionAttributeListenerTest() { }
    
        public void attributeAdded(HttpSessionBindingEvent sbe) {
            HttpSession session = sbe.getSession();
            String name= sbe.getName();    //新添加的属性名
            System.out.println("新建Session属性:" + name + ",值为:" + sbe.getValue());
        }
    
        public void attributeRemoved(HttpSessionBindingEvent sbe) {
            HttpSession session = sbe.getSession();
            String name= sbe.getName();    //即将删除的属性名
            System.out.println("删除Session属性:" + name + ",值为:" + sbe.getValue());
        }
    
        public void attributeReplaced(HttpSessionBindingEvent sbe) {
            HttpSession session = sbe.getSession();
            String name= sbe.getName();    //发生修改的属性名
            Object oldValue = sbe.getValue();   //原来的属性值
            System.out.println("修改Session属性:" + name + ",旧值为:" + oldValue +"新值为:" + session.getAttribute(name));
        }
    }
    

    监听Session内的对象

    除了上面6种Listener,另外还有两种Listener用于监控Session内的对象,分别是HttpSessionBindingListener与HttpSessionActivationListener。他们触发的时机为:

    • HttpSessionBindingListener:当监听对象与Session绑定时执行valueBound方法,解绑时执行valueUnbound方法。
    • HttpSessionActivationListener:服务器关闭时,会将Session里的内容保存到硬盘上,这个过程称为钝化,执行sessionWillPassivate方法。服务器重新启动时,会将Session内容从硬盘上重新加载,会执行sessonDidActivate方法。

    案例:把User对象与Session绑定时,就会执行相应的方法。

    package model;
    /**
     * Created by kindleheart happily.
     */
    
    import javax.servlet.http.*;
    
    public class User implements HttpSessionBindingListener, HttpSessionActivationListener {
        private String name;
        private int age;
    
        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public User() {
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public void sessionWillPassivate(HttpSessionEvent se) {
            HttpSession session = se.getSession();
            System.out.println(this + "已经成功从硬盘加载。SessionId:" + session.getId());
        }
    
        @Override
        public void sessionDidActivate(HttpSessionEvent se) {
            HttpSession session = se.getSession();
            System.out.println(this + "即将保存到硬盘。SessionId:" + session.getId());
        }
    
        @Override
        public void valueBound(HttpSessionBindingEvent event) {
            HttpSession session = event.getSession();
            String name = event.getName();
            System.out.println(this + "被绑定到Session" + session.getId() + "的" + name + "属性上");
        }
    
        @Override
        public void valueUnbound(HttpSessionBindingEvent event) {
            HttpSession session = event.getSession();
            String name = event.getName();
            System.out.println(this + "被从Session" + session.getId() + "的" + name + "属性上移除");
        }
    }
    

    应用:统计在线人数

    用户第一次访问服务器时,服务器会创建一个Session,用户结束访问时会销毁这个Session,那么可以使用HttpSessionListener来统计在线人数。

    package util;
    /**
     * Created by kindleheart happily.
     */
    
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.annotation.WebListener;
    import javax.servlet.http.HttpSessionAttributeListener;
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    import javax.servlet.http.HttpSessionBindingEvent;
    
    @WebListener()
    public class OnlineNumListener implements HttpSessionListener {
        private static int userNum = 0;
    
        public OnlineNumListener() {
        }
    
        public static int getUserNum() {
            return userNum;
        }
    
        public void sessionCreated(HttpSessionEvent se) {
            userNum++;
        }
    
        public void sessionDestroyed(HttpSessionEvent se) {
            userNum--;
        }
    }
    

     在主页显示在线人数:

    <%@ page import="util.OnlineNumListener" %>
    <%@page pageEncoding="utf-8" contentType="text/html; utf-8" language="java" isELIgnored="false" %>
    <html>
    <body>
    <h2>我是主页</h2>
    <%
        int num = OnlineNumListener.getUserNum();
    %>
    <h3>在线人数为:</h3>><%=num%>
    </body>
    </html>
    
    作者:kindleheart
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    for 续1
    8 解决多线程对共享数据出错
    7 多线程 全局变量
    6 线程threading
    5 多进程copy文件
    4 进程间通信Queue [kjuː]
    3 进程池
    2 进程multiprocessing [mʌltɪ'prəʊsesɪŋ] time模块
    1 多任务fork Unix/Linux/Mac
    16 pep8 编码规范
  • 原文地址:https://www.cnblogs.com/kindleheart/p/9780787.html
Copyright © 2020-2023  润新知