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属性上

posted @   技术研究与问题解决  阅读(205)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 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递归用法
点击右上角即可分享
微信分享提示