Hello,Web Listener

本贴最后更新于 2709 天前,其中的信息可能已经时移世改

Hello,Web Listener

这是一篇供笔记性质的博文,仅用于帮助基础知识的记忆。

定义

web 监听器是 Servlet 规范中定义的一种特殊类,可以监听客户端的请求,也可以监听服务端的操作。监听的对象包括:ServletContent、HttpSession 以及 ServletRequest 等域对象。这三个对象,分别对应 application、session 和 request 对象,可以监听它们的创建、销毁以及属性变化的事件,并在这些事件发生前、发生后,做一些必要的处理。

用途

  • 统计在线人数和在线用户

  • 系统启动时加载初始化信息(缓存、公用链接等)

  • 统计网站访问量

  • 跟 spring 结合

创建一个 web 监听器

相关源码请见 jsp-basic

  • 创建一个新的 listener 包,包下创建一个 implements 于 ServletContextListener 的类,类下实现两个方法,contextInitialized 和 contextDestroyed。具体例子如:

      package  com.liumapp.jspbasic.listener;
    
      import  javax.servlet.ServletContextEvent;
      import  javax.servlet.ServletContextListener;
    
      /**
       * Created by liumapp on 6/1/17. * E-mail:liumapp.com@gmail.com * home-page:http://www.liumapp.com */public  class  FirstListener  implements  ServletContextListener{
    
      	public  void  contextInitialized(ServletContextEvent  servletContextEvent) {
      		System.out.println("initialized");
        }
    
      	public  void  contextDestroyed(ServletContextEvent  servletContextEvent) {
      		System.out.println("destroyed");
        }
    
      }
    
  • 配置 web.xml 文件,添加如下代码:

      <listener>
      	<listener-class>com.liumapp.jspbasic.listener.FirstListenerlistener-class>
      <listener>
    
  • 到此,第一个 web 监听器创建完成

监听器启动顺序

  • 多个监听器的启动顺序按照 web.xml 中的加载顺序来定义

  • 优先级:监听器 > 过滤器 > Servlet

监听器的分类

ServletContext

用于监听应用程序环境对象的事件监听器

HttpSession

用于监听用户会话对象的事件监听器

ServletRequest

用于监听请求消息对象的事件监听器

按事件划分

监听域对象自身的创建和销毁的事件监听器

  • ServletContext->ServletContextListener,在项目中,可以定义多个 ServletContextListener,但只会有一个 ServletContext 对象。一般用于做定时器,或者加载全局属性对象,缓存、数据库连接等。我们创建第一个 web 监听器用到的就是 ServletContextListener。

  • HttpSession->HttpSessionListener,具体请看下方代码:

      package  com.liumapp.jspbasic.listener;
    
      import  javax.servlet.http.HttpSessionEvent;
      import  javax.servlet.http.HttpSessionListener;
    
      /**
       * Created by liumapp on 6/2/17. * E-mail:liumapp.com@gmail.com * home-page:http://www.liumapp.com */
       public  class  FirstHttpSessionListener  implements  HttpSessionListener {
    
      	public  void  sessionCreated(HttpSessionEvent  httpSessionEvent) {
      		System.out.println("sessionCreated");
        }
    
      	/**
       * 配置文件中设置了session的超时时间为1分钟,但实际所需要的时间是1分半才会执行sessionDestroy. * @param httpSessionEvent
        */
        public  void  sessionDestroyed(HttpSessionEvent  httpSessionEvent) {
      		System.out.println("sessionDestroyed");
        }
      }
    
  • ServletRequest->ServletRequestListener,在项目中,可以定义多个 ServletRequestListener,但只会有一个 ServletRequest 对象。具体代码如下所示

      package  com.liumapp.jspbasic.listener;
    
      import  javax.servlet.ServletRequestEvent;
      import  javax.servlet.ServletRequestListener;
    
      /**
       * Created by liumapp on 6/2/17. * E-mail:liumapp.com@gmail.com * home-page:http://www.liumapp.com */
       public  class  FirstServletRequestListener  implements  ServletRequestListener {
      	public  void  requestDestroyed(ServletRequestEvent  servletRequestEvent) {
      		System.out.println("requestDestroyed");
        }
    
      	public  void  requestInitialized(ServletRequestEvent  servletRequestEvent) {
      		String  name = servletRequestEvent.getServletRequest().getParameter("name"); // by get method
        System.out.println("requestInitialized and name is :" + name);
        }
      }
    

监听域对象中的属性的增加和删除的事件监听器

  • ServletContext->ServletContextAttributeListener

  • HttpSession->HttpSessionAttributeListener

  • ServletRequest->ServletRequestAttributeListener

上面三个监听器的用法都是一样的,代码的例子就举一个吧,下面的例子表示,监听器会监听属性的创建、删除和替换这三个事件,然后触发事件。

package  com.liumapp.jspbasic.listener;

import  javax.servlet.ServletContextAttributeEvent;
import  javax.servlet.ServletContextAttributeListener;

/**
 * Created by liumapp on 6/2/17. * E-mail:liumapp.com@gmail.com * home-page:http://www.liumapp.com */
 public  class  FirstServletContextAttributeListener implements  ServletContextAttributeListener {
	public  void  attributeAdded(ServletContextAttributeEvent  servletContextAttributeEvent) {
		System.out.println("servletContextAttribute added , name is : " + servletContextAttributeEvent.getName());
  }

	public  void  attributeRemoved(ServletContextAttributeEvent  servletContextAttributeEvent) {
		System.out.println("servletContextAttribute removed , name is : " + servletContextAttributeEvent.getName());
  }

	public  void  attributeReplaced(ServletContextAttributeEvent  servletContextAttributeEvent) {
		System.out.println("servletContextAttribute replaced , name is : " + servletContextAttributeEvent.getName());
  }
}

监听绑定到 HttpSession 域中的某个对象的的状态的事件监听器

HttpSession 中的对象状态分为:

  • 绑定-> 解除绑定

    绑定就是通过 session 的 setAttribute 添加一个 session 属性,解除绑定就是通过 removeAttribute 删除一个 session 属性。

  • 钝化-> 活化

    钝化就是将 session 持久性的保存在 database 或者 redis 上面,活化就是将 session 从 database 或者 redis 上面恢复到原有的保存方式。

session 钝化机制

把服务器中不经常使用的 session 对象暂时序列化到文件系统或是数据库系统中,当被使用时反序列化到内存中,整个过程由服务器自动完成。

Tomcat 中的两种 session 钝化管理机制
  • org.apache.catalina.session.StandardManager

    1. 当 Tomcat 服务器被关闭或者重启时,Tomcat 服务器会将当前内存中的 Session 对象钝化到服务器文件系统中;
    2. 当 Web 应用程序被重新加载时,内存中的 Session 对象也会被钝化到服务器的文件系统中;
    3. 钝化后的文件被保存在 Tomcat 安装路径/work/Catalina/hostname/applicationname/SESSION.ser
  • org.apache.catalina.session.PersistentManager

    1. 首先在钝化的基础上进行了扩张。第一种情况如上面的第一点,第二种情况如上面的第二点,第三种情况,可以配置主流内存的 Session 对象数目,将不常使用的 Session 对象保存到文件系统或者数据库,当用时再加载;
    2. 默认情况下,Tomcat 提供两个钝化驱动类:org.apache.catalina.FileStore 和 org.apache.catalina.JdbcStore。

好像扯远了......

现在回到监听器上来......

请注意,以下两个监听器不需要在 web.xml 进行注册。

  • HttpSessionBindingListener

    1. 绑定:valueBound 方法
    2. 解除绑定:valueUnbound 方法

    实现这个接口的时候,并不是创建一个 Listener 来实现,而是创建一个普通的 JavaBean 来实现。因为最终修改的是一个普通的对象的状态,而不是监听器的状态。这里我们举的例子如下:

      package  com.liumapp.jspbasic.entity;
    
      import  javax.servlet.http.HttpSessionBindingEvent;
      import  javax.servlet.http.HttpSessionBindingListener;
    
      /**
       * Created by liumapp on 6/2/17. * E-mail:liumapp.com@gmail.com * home-page:http://www.liumapp.com */
       public  class  User  implements  HttpSessionBindingListener {
    
        private  String  userName;
    
        private  String  passWord;
    
        public  void  valueBound(HttpSessionBindingEvent  httpSessionBindingEvent) {
      		System.out.println("user valueBound , name is : " + httpSessionBindingEvent.getName());
        }
    
      	public  void  valueUnbound(HttpSessionBindingEvent  httpSessionBindingEvent) {
      		System.out.println("user valueUnBound , name is : " + httpSessionBindingEvent.getName());
        }
    
      	public  String  getUserName() {
      		return  userName;
        }
    
      	public  String  getPassWord() {
      		return  passWord;
        }
    
      	public  void  setUserName(String  userName) {
      		this.userName = userName;
        }
    
      	public  void  setPassWord(String  passWord) {
      		this.passWord = passWord;
        }
    
      }
    

    随后我们通过下面的两行代码即可实现 bound 和 unbound 事件的触发:

      request.getSession().setAttribute("currentUser" , new  com.liumapp.jspbasic.entity.User());
    
      request.getSession().removeAttribute("currentUser");
    
  • HttpSessionActivationListener

    1. 钝化:sessionWillPassivate 方法
    2. 活化:sessionDidActive 方法

    代码如下所示:

      package  com.liumapp.jspbasic.entity;
    
      import  sun.plugin2.message.Serializer;
    
      import  javax.servlet.http.HttpSessionActivationListener;
      import  javax.servlet.http.HttpSessionBindingEvent;
      import  javax.servlet.http.HttpSessionBindingListener;
      import  javax.servlet.http.HttpSessionEvent;
      import  java.io.Serializable;
    
      /**
       * Created by liumapp on 6/2/17. * E-mail:liumapp.com@gmail.com * home-page:http://www.liumapp.com */
       public  class  User  implements  HttpSessionBindingListener , HttpSessionActivationListener , Serializable {
    
        private  String  userName;
    
        private  String  passWord;
    
        public  void  valueBound(HttpSessionBindingEvent  httpSessionBindingEvent) {
      		System.out.println("user valueBound , name is : " + httpSessionBindingEvent.getName());
        }
    
      	public  void  valueUnbound(HttpSessionBindingEvent  httpSessionBindingEvent) {
      		System.out.println("user valueUnBound , name is : " + httpSessionBindingEvent.getName());
        }
    
      	public  String  getUserName() {
      		return  userName;
        }
    
      	public  String  getPassWord() {
      		return  passWord;
        }
    
      	public  void  setUserName(String  userName) {
      		this.userName = userName;
        }
    
      	public  void  setPassWord(String  passWord) {
      		this.passWord = passWord;
        }
    
      	//钝化
        public  void  sessionWillPassivate(HttpSessionEvent  httpSessionEvent) {
      		System.out.println("sessionWillPassivate : " + httpSessionEvent.getSource());
        }
    
      	//活化
        public  void  sessionDidActivate(HttpSessionEvent  httpSessionEvent) {
      		System.out.println("sessionDidActivate : " + httpSessionEvent.getSource());
        }
      }
    

    我们进入 init 页面后停止 tomcat 服务器,session 会自动序列化之后存入文件系统中,相关信息如下所示:

      sessionWillPassivate : org.apache.catalina.session.StandardSessionFacade@4666d1cf
    

    第二次启动 Tomcat 之后,session 信息将会反序列化然后被加载,我们可以在 index.jsp 看到输入的 session 信息,同时请注意,这里还需要引入 Serializable 的接口实现,不然无法成功反序列化。

上面的描述都是 Tomcat 的第一种 session 钝化管理机制,那么第二种 PersistentManager 如何使用呢?

首先我们进入 Tomcat/conf 目录,打开 context.xml 文件,找到如下的代码

<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->

把 manager 的 pathname 设置为 FileStore 或者 JdbcStore,两者类型的详细信息下回分解。

Servlet3.0 下面监听器的使用

前文的描述都是针对 Servlet2.5 版本来进行的,那么在 Servlet3.0 下面,我们需要做的,就是不需要在 web.xml 下面进行 listener 的任何注解,只需要在 listener 类的前面,加一个注解即可,如下:

@WebListener("this is my web listener")
class ....
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3186 引用 • 8212 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...