,好记性不如烂笔头
当Web应用在Web容器中运行时,Web应用内部会不断地发生各种事件:如Web应用被启动、Web应用被停止、用户session开始、用户session结束等。通常这些Web操作对开发者是透明的,但Servlet API也提供了相应的接口来监控这些变化。
当我们要使用Listener时,只需要两个步骤:
① 定义Listener实现类(实现对应的接口)② 通过Annotation或在web.xml文件中配置Listener1、实现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"); } }}