,好记性不如烂笔头


当Web应用在Web容器中运行时,Web应用内部会不断地发生各种事件:如Web应用被启动、Web应用被停止、用户session开始、用户session结束等。通常这些Web操作对开发者是透明的,但Servlet API也提供了相应的接口来监控这些变化。

当我们要使用Listener时,只需要两个步骤:

① 定义Listener实现类(实现对应的接口)
② 通过Annotation或在web.xml文件中配置Listener

1、实现Listener接口

不同的Web事件对应的监听器也不同,常用的Web事件监听器接口有如下几个:

  • 1.1 Servlet Context Events

->ServletContextListener:用于监听Web应用的启动和关闭->ServletContextAttributeListener:用于监听ServletContext范围(application)内属性的改变
  • 1.2 Http Session Events

->HttpSessionListener:用于监听用户session的开始和结束->HttpSessionAttributeListener:用于监听HttpSession范围(session)内属性的改变->HttpSessionActivationListener:session的passivation是指非活动的session被写入持久设备,activate是反过程。                 一般情况下和HttpSessionBindingListener一起使用。->HttpSessionBindingListener:实现HttpSessionBindingListener接口的对象被绑定到session时                触发valueBound事件,解除绑定时触发valueUnbound事件。
  • 1.3 Servlet Request Events

->ServletRequestListener:用于监听用户请求->ServletRequestAttributeListener:用于监听ServletRequest范围(request)内属性的改变

一般来说,需要监听哪些Web事件就实现对应接口的方法即可。

2、配置Listener

实现了Listener类之后,还需要配置Listener,可以选择Annotaion方式或web.xml方式。

  • Annotation方式

只需使用@WebListener修饰Listener实现类即可(要求Servlet3.0以上)

@WebListenerpublic class MyHttpSessionListener implements HttpSessionListener {......}
  • web.xml方式

     
     
com.invicme.apps.shiro.listener.XXXListener

说明:

    在线人数统计网上一般的实现方式是实现HttpSessionListener,监控session的创建(create)和销毁(destroy),但在实际的使用过程中,发现destroy并不及时并且在session.invalidate()的时候还会调用一次sessionCreated()。

package com.invicme.apps.shiro.listener; import java.util.ArrayList;import java.util.List;import javax.servlet.ServletContext;import javax.servlet.http.HttpSession;import javax.servlet.http.HttpSessionBindingEvent;import javax.servlet.http.HttpSessionBindingListener; public class OnlineUserBindingListener implements HttpSessionBindingListener {    String username;         public OnlineUserBindingListener(String username){        this.username = username;    }    public void valueBound(HttpSessionBindingEvent event) {        HttpSession session = event.getSession();        ServletContext application = session.getServletContext();        // 把用户名放入在线列表        List onlineUserList = (List) application.getAttribute("onlineUserList");        // 第一次使用前,需要初始化        if (onlineUserList == null) {            onlineUserList = new ArrayList();            application.setAttribute("onlineUserList", onlineUserList);        }        onlineUserList.add(this.username);    }     public void valueUnbound(HttpSessionBindingEvent event) {        HttpSession session = event.getSession();        ServletContext application = session.getServletContext();         // 从在线列表中删除用户名        List onlineUserList = (List) application.getAttribute("onlineUserList");        onlineUserList.remove(this.username);        System.out.println(this.username + "退出。");    }}

在LoginController中,每次登录成功之后可以执行一次,session.setAttribute("loginUserLS", new OnlineUserBindingListener(username))

3、Listener示例

  • 3.1 Servlet Context Events

package com.invicme.apps.shiro.listener.context;import javax.servlet.ServletContextEvent;import javax.servlet.ServletContextListener;import javax.servlet.annotation.WebListener;import org.apache.log4j.Logger;/** * @author lucl * Interface for receiving notification events about ServletContext lifecycle changes. */@WebListenerpublic class MyServletContextListener implements ServletContextListener {    private static final Logger logger = Logger.getLogger(MyServletContextListener.class);        public MyServletContextListener() {        logger.info("MyServletContextListener() was invoke...");    }    // Web容器启动的时候执行改方法    public void contextInitialized(ServletContextEvent sce)  {         logger.info("contextInitialized() was invoke.");    }    // Web容器reload应用时,首先destroy,然后再initialize    public void contextDestroyed(ServletContextEvent sce)  {         logger.info("contextDestroyed() was invoke.");    }    }package com.invicme.apps.shiro.listener.context;import javax.servlet.ServletContextAttributeEvent;import javax.servlet.ServletContextAttributeListener;import javax.servlet.annotation.WebListener;import org.apache.log4j.Logger;/** * @author lucl * Interface for receiving notification events about ServletContext attribute changes.  */@WebListenerpublic class MyServletContextAttributeListener implements ServletContextAttributeListener {        private static final Logger logger = Logger.getLogger(MyServletContextAttributeListener.class);        /**     * Default constructor.      */    public MyServletContextAttributeListener() {        logger.info("MyServletContextAttributeListener() was invoke...");     }    // context.setAttribute()    public void attributeAdded(ServletContextAttributeEvent event)  {         logger.info("attributeAdded() was invoke...");     }        // context.setAttribute(已设置过的属性)    public void attributeReplaced(ServletContextAttributeEvent event)  {         logger.info("attributeReplaced() was invoke...");     }        // context.removeAttribute()    public void attributeRemoved(ServletContextAttributeEvent event)  {         logger.info("attributeRemoved() was invoke...");     }    }

  • 3.2 Http Session Events

package com.invicme.apps.shiro.listener.session;import javax.servlet.annotation.WebListener;import javax.servlet.http.HttpSessionEvent;import javax.servlet.http.HttpSessionListener;import org.apache.log4j.Logger;/** * @author lucl * Interface for receiving notification events about HttpSession lifecycle changes.  */@WebListenerpublic class MyHttpSessionListener implements HttpSessionListener {    private static final Logger logger = Logger.getLogger(MyHttpSessionListener.class);        /**     * Default constructor.      */    public MyHttpSessionListener() {        logger.info("MyHttpSessionListener() was invoke...");     }    // 会话建立(如:request.getSession())    public void sessionCreated(HttpSessionEvent se)  {         logger.info("sessionCreated() was invoke...");     }    public void sessionDestroyed(HttpSessionEvent se)  {         logger.info("sessionCreated() was invoke...");     }    }package com.invicme.apps.shiro.listener.session;import javax.servlet.annotation.WebListener;import javax.servlet.http.HttpSessionAttributeListener;import javax.servlet.http.HttpSessionBindingEvent;import org.apache.log4j.Logger;/** * @author lucl * Interface for receiving notification events about HttpSession attribute changes.  */@WebListenerpublic class MyHttpSessionAttributeListener implements HttpSessionAttributeListener {    private static final Logger logger = Logger.getLogger(MyHttpSessionAttributeListener.class);    /**     * Default constructor.      */    public MyHttpSessionAttributeListener() {        logger.info("MyHttpSessionAttributeListener() was invoke...");     }    // session.setAttribute()    public void attributeAdded(HttpSessionBindingEvent event)  {         logger.info("attributeAdded() was invoke...");     }    // session.setAttribute(已经设置过的属性)    public void attributeReplaced(HttpSessionBindingEvent event)  {         logger.info("attributeReplaced() was invoke...");     }        // session.removeAttribute()    public void attributeRemoved(HttpSessionBindingEvent event)  {         logger.info("attributeRemoved() was invoke...");     }}package com.invicme.apps.shiro.listener.session;import javax.servlet.annotation.WebListener;import javax.servlet.http.HttpSessionBindingEvent;import javax.servlet.http.HttpSessionBindingListener;import org.apache.log4j.Logger;/** * @author lucl * Causes an object to be notified when it is bound to or unbound from a session.  */@WebListenerpublic class MyHttpSessionBindingListener implements HttpSessionBindingListener {    private static final Logger logger = Logger.getLogger(MyHttpSessionBindingListener.class);    /**     * Default constructor.      */    public MyHttpSessionBindingListener() {        logger.info("MyHttpSessionBindingListener() was invoke...");     }    public void valueUnbound(HttpSessionBindingEvent event)  {         logger.info("valueUnbound() was invoke...");     }    public void valueBound(HttpSessionBindingEvent event)  {         logger.info("valueBound() was invoke...");     }    }

  • 3.3 Servlet Request Events

package com.invicme.apps.shiro.listener.request;import javax.servlet.ServletRequestEvent;import javax.servlet.ServletRequestListener;import javax.servlet.annotation.WebListener;import org.apache.log4j.Logger;/** * @author lucl * Interface for receiving notification events about requests coming into and going out of scope of a web application.  */@WebListenerpublic class MyServletRequestListener implements ServletRequestListener {    private static final Logger logger = Logger.getLogger(MyServletRequestListener.class);    /**     * Default constructor.      */    public MyServletRequestListener() {        logger.info("MyServletRequestListener() was invoke...");     }    // 每次Http请求都是一个request,方法调用一次    public void requestInitialized(ServletRequestEvent sre)  {         logger.info("requestInitialized() was invoke...");     }        // 一次request请求执行完毕    public void requestDestroyed(ServletRequestEvent sre)  {         logger.info("requestDestroyed() was invoke...");     }    }package com.invicme.apps.shiro.listener.request;import javax.servlet.ServletRequestAttributeEvent;import javax.servlet.ServletRequestAttributeListener;import javax.servlet.annotation.WebListener;import org.apache.log4j.Logger;/** * @author lucl * Interface for receiving notification events about ServletRequest attribute changes.  */@WebListenerpublic class MyServletRequestAttributeListener implements ServletRequestAttributeListener {    private static final Logger logger = Logger.getLogger(MyServletRequestAttributeListener.class);    /**     * Default constructor.      */    public MyServletRequestAttributeListener() {        logger.info("MyServletRequestAttributeListener() was invoke...");     }    public void attributeAdded(ServletRequestAttributeEvent srae)  {         logger.info("attributeAdded() was invoke...");    }    public void attributeReplaced(ServletRequestAttributeEvent srae)  {         logger.info("attributeReplaced() was invoke...");    }    public void attributeRemoved(ServletRequestAttributeEvent srae)  {         logger.info("attributeRemoved() was invoke...");    }    }

4、Listener监听测试Servlet

package com.invicme.apps.shiro.servlet;import java.io.IOException;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import org.apache.log4j.Logger;import com.invicme.apps.shiro.listener.session.MyHttpSessionBindingListener;/** * @author lucl */@WebServlet("/httpServlet")public class MyHttpServlet extends HttpServlet {    private static final long serialVersionUID = 1L;        private static final Logger logger = Logger.getLogger(MyHttpServlet.class);           public MyHttpServlet() {        super();    }    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        doPost(request, response);    }    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {        // Servlet Context Attribute Event        {            ServletContext servletContext = request.getServletContext();            // attributeAdded            logger.info("=============servletContext.setAttribute");            servletContext.setAttribute("sc_name", "sc_value");            logger.info("=============servletContext.attributeReplaced");            servletContext.setAttribute("sc_name", "sc_value");            logger.info("=============servletContext.removeAttribute");            servletContext.removeAttribute("sc_name");        }        // Session Event        {            logger.info("=============request.getSession()=>sessionCreated");            HttpSession session = request.getSession();            logger.info("=============session.setAttribute()");            session.setAttribute("s_name", "s_value");            logger.info("=============session.attributeReplaced()");            session.setAttribute("s_name", "s_value");            logger.info("=============session.removeAttribute()");            session.removeAttribute("s_name");            // 实现HttpSessionBindingListener接口的对象被绑 定到session时触发valueBound事件,解除绑定时触发valueUnbound事件。            MyHttpSessionBindingListener bindingListener = new MyHttpSessionBindingListener();            logger.info("=============session.setAttribute(\"bind\", bindingListener)");            session.setAttribute("bind", bindingListener);            logger.info("=============session.removeAttribute(\"bind\")");            session.removeAttribute("bind");                        logger.info("=============session.invalidate()=>sessionDestroyed");            session.invalidate();        }                // Request Event        {            logger.info("=============request.setAttribute()");            request.setAttribute("r_name", "r_value");            logger.info("=============request.attributeReplaced()");            request.setAttribute("r_name", "r_value");            logger.info("=============request.removeAttribute()");            request.removeAttribute("r_name");        }    }}