0%

Hello,Web Listener

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 ....