Listener的分类
Servlet 2.5规范中共有8中Listener,现在主流用的4.0.分别用于监听Session、context、request等的创建于销毁、属性变化等。
另有一个Listener能够监听存放在Session中的对象。共有6中Event。
监听对象的创建 与销毁
ServletContextListener, HttpSessionListener, ServletRequestListener分别用于监控Session、Context、request的创建与销毁。触发时机分别为:
- HttpSessionListener:监听Session的创建与销毁。创建Session时执行sessionCreated(HttpSessionEvent se)方法。超时或者执行session.invalidate()时,执行sessionDestroyed(HttpSessionEvent se) 方法。该Listener可用于收集在线者信息。
- ServletContextListener:监听context的创建与销毁。context带包当前的Web应用程序。服务器启动或者热部署war包时执行contextInitialized(ServletContextEvent sce)方法。服务器关闭时或者只关闭该Web时执行contextDestroyed(ServletContextEvent sce) 方法。该Listener可用于启动时获取web.xml里配置的初始化参数。
- ServletRequestListener:监听request的创建与销毁。用户每次请求request都会执行rrequestInitialized(ServletRequestEvent servletRequestEvent)方法。request处理完毕自动销毁前执行requestDestroyed(ServletRequestEvent servletRequestEvent)方法。注意如果一个HTML页面内含有多个图片,则请求一次HTML页面可能会触发多次request事件。
实例:监听Session、request与ServletContext
package com.wht.demo.listener; /** * @author JDIT */ import org.apache.log4j.Logger; 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 SessionListenerTest implements ServletContextListener, HttpSessionListener, ServletRequestListener { private Logger logger = Logger.getLogger(this.getClass()); //日志记录工具 // Public constructor is required by servlet spec public SessionListenerTest() { } public void contextInitialized(ServletContextEvent sce) { ServletContext context = sce.getServletContext(); logger.info("===============================即将开启" + context.getContextPath()); } public void contextDestroyed(ServletContextEvent sce) { ServletContext context = sce.getServletContext(); logger.info("===============================即将开启" + context.getContextPath()); } public void requestDestroyed(ServletRequestEvent servletRequestEvent) { HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest(); long time = System.currentTimeMillis() - (Long) request.getAttribute("dateCreated"); logger.info(request.getRemoteAddr() + "请求处理结束,用时" + time + "毫秒。"); } public void requestInitialized(ServletRequestEvent servletRequestEvent) { HttpServletRequest request = (HttpServletRequest) servletRequestEvent.getServletRequest(); String uri = request.getRequestURI(); uri = request.getQueryString() == null ? uri : (uri + "?" + request.getQueryString()); request.setAttribute("dateCreated", System.currentTimeMillis()); logger.info("IP" + request.getRemoteAddr() + "请求" + uri); } // ------------------------------------------------------- // HttpSessionListener implementation // ------------------------------------------------------- public void sessionCreated(HttpSessionEvent se) { HttpSession session = se.getSession(); logger.info("===============================创建一个Session,ID 为" + session.getId()); } public void sessionDestroyed(HttpSessionEvent se) { HttpSession session = se.getSession(); logger.info("===============================销毁一个Session,ID 为" + session.getId()); } }
[INFO ] 2020-02-22 17:32:15,971 method:com.wht.demo.servlet.HelloServlet.init(HelloServlet.java:27)
执行 int() 方法…
[2020-02-22 05:32:15,991] Artifact HelloWorld:war exploded: Artifact is deployed successfully
[2020-02-22 05:32:15,991] Artifact HelloWorld:war exploded: Deploy took 622 milliseconds
[INFO ] 2020-02-22 17:32:16,471 method:com.wht.demo.listener.SessionListenerTest.requestInitialized(SessionListenerTest.java:46)
IP127.0.0.1请求/FirstWeb/index.jsp
[INFO ] 2020-02-22 17:32:17,021 method:com.wht.demo.listener.SessionListenerTest.sessionCreated(SessionListenerTest.java:54)
===============================创建一个Session,ID 为6A26A5D922EA35C0A336AE1FF3C11BFF
[INFO ] 2020-02-22 17:32:17,021 method:com.wht.demo.listener.SessionListenerTest.requestDestroyed(SessionListenerTest.java:37)
127.0.0.1请求处理结束,用时550毫秒。
[INFO ] 2020-02-22 17:32:17,659 method:com.wht.demo.listener.SessionListenerTest.requestInitialized(SessionListenerTest.java:46)
IP0:0:0:0:0:0:0:1请求/FirstWeb/index.jsp
[INFO ] 2020-02-22 17:32:17,660 method:com.wht.demo.listener.SessionListenerTest.sessionCreated(SessionListenerTest.java:54)
===============================创建一个Session,ID 为D8D2DEF4EAA16E54CE1D2556EB72A330
[INFO ] 2020-02-22 17:32:17,660 method:com.wht.demo.listener.SessionListenerTest.requestDestroyed(SessionListenerTest.java:37)
0:0:0:0:0:0:0:1请求处理结束,用时1毫秒。
监听对象的属性变化
另一类Listener用于监听Session、context、request的属性变化,接口名称格式为xxxAttributeListener,包括HttpSessionAttributeListener、ServletContextAttributeListener、ServletRequestAtrributeListener。当向被监听对象中添加、更新、移除属性时,会分别执行xxxAdded()、xxxReplaceded()、xxxRemoved()方法,xxx分别代表Session、context、request:
package com.wht.demo.listener; /** * @author JDIT */ import org.apache.log4j.Logger; import javax.servlet.annotation.WebListener; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; @WebListener() public class SessionAttributeListenerTest implements HttpSessionAttributeListener { private final Logger logger = Logger.getLogger(this.getClass()); public void attributeAdded(HttpSessionBindingEvent sbe) { String name = sbe.getName(); logger.info("新建的" + name + ",值为:" + sbe.getValue()); } public void attributeRemoved(HttpSessionBindingEvent sbe) { String name = sbe.getName(); logger.info("移除的" + name + ",值为:" + sbe.getValue()); } public void attributeReplaced(HttpSessionBindingEvent sbe) { String name = sbe.getName(); logger.info("修改的" + name + ",值为:" + sbe.getValue()); } }
监听Session内的对象
除了上面的6中Listener,还有两种Listener用于监控Session内的对象,分别是HttpSessionBindingListener与HttpSessionActivationListener。它们的触发时机分别为:
- HttpSessionBindingListener:当对象被放到Session里是执行 valueBound(HttpSessionBindingEvent httpSessionBindingEvent)方法。当对象被从Session里移除时执行valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent)方法。对象必须实现该Listener接口。
- HttpSessionActivationListener:服务器关闭时,会将Session里的内容保存到硬盘上,这个过程叫做钝化。服务器重新启动时,会将Session内容从硬盘上重新加载。当Session里的对象被钝化时会执行sessionWillPassivate(HttpSessionEvent httpSessionEvent)方法,当对象被重新加载时执行sessionDidActivate(HttpSessionEvent httpSessionEvent)。对象必须实现该Listener接口。
package com.wht.demo.listener; import org.apache.log4j.Logger; import javax.servlet.http.*; import java.io.Serializable; import java.util.Date; /** * @author JDIT */ public class PersonInfo implements HttpSessionBindingListener, HttpSessionActivationListener, Serializable { private final Logger logger = Logger.getLogger(this.getClass()); private Date dateCreated; private String name; public Date getDateCreated() { return dateCreated; } public void setDateCreated(Date dateCreated) { this.dateCreated = dateCreated; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void sessionWillPassivate(HttpSessionEvent httpSessionEvent) { //即将被钝化到硬盘时被调用 HttpSession session = httpSessionEvent.getSession(); logger.info(this + "即将保存到硬盘。sessionId:" + session.getId()); } public void sessionDidActivate(HttpSessionEvent httpSessionEvent) { //从硬盘恢复被调用 HttpSession session = httpSessionEvent.getSession(); logger.info(this + "已经成功从硬盘加载。sessionId:" + session.getId()); } public void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) { //被放进Session前被调用 HttpSession session = httpSessionBindingEvent.getSession(); String name = httpSessionBindingEvent.getName(); logger.info(this + "被绑定到session" + session.getId() + "的" + name + "属性上"); this.setDateCreated(new Date()); } public void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) { //从session中被移除后调用 HttpSession session = httpSessionBindingEvent.getSession(); String name = httpSessionBindingEvent.getName(); logger.info(this + "被从到session" + session.getId() + "的" + name + "属性上移除"); } @Override public String toString() { return "PersonInfo{" + "dateCreated=" + dateCreated + ", name='" + name + '\'' + '}'; } }
与上面6种Listener不同,这两个Listener监听的是Session中的对象而非Session等,因此不需要在web.xml中声明。使用示例:
<%@ page import="com.wht.demo.listener.PersonInfo" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>My First Page</title> </head> <body> <center> <h1> <% PersonInfo personInfo = (PersonInfo) session.getAttribute("personInfo"); if (personInfo == null) { personInfo = new PersonInfo(); personInfo.setName("WHT"); session.setAttribute("personInfo", personInfo); out.println("personInfo 对象不存在。已经成功新建。sessionId:" + session.getId()); }else { out.println("personInfo 对象存在。无需创建。sessionId:" + session.getId()); } %> </h1> </center> </body> </html>
PersonInfo对象被放进、移出Session或者启动、关闭服务器都会触发PersonInfo内的Listener事件。运行结果:
[INFO ] 2020-02-22 18:16:00,394 method:com.wht.demo.servlet.HelloServlet.init(HelloServlet.java:27)
执行 int() 方法…
[2020-02-22 06:16:00,417] Artifact HelloWorld:war exploded: Artifact is deployed successfully
[2020-02-22 06:16:00,417] Artifact HelloWorld:war exploded: Deploy took 575 milliseconds
[INFO ] 2020-02-22 18:16:01,520 method:com.wht.demo.listener.PersonInfo.valueBound(PersonInfo.java:49)
PersonInfo{dateCreated=null, name=‘WHT’}被绑定到sessionD289E0B0702ABBBF6DD442DAB252C646的personInfo属性上
[INFO ] 2020-02-22 18:16:01,749 method:com.wht.demo.listener.PersonInfo.valueBound(PersonInfo.java:49)
PersonInfo{dateCreated=null, name=‘WHT’}被绑定到session9A3DDB3952807A8A904486CEF220DD38的personInfo属性上
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
2019-08-08 如何使用start with connect by prior递归用法