Servlet中的8大监听器

1 概述

  • Listener用于监听servlet中的事件,例如contextrequestsession对象的创建、修改、删除,并触发响应事件。
  • Listener是观察者模式的实现,在servlet中主要用于对contextrequestsession对象的生命周期进行监控。在servlet2.5规范中共定义了8中Listener

2 Servlet三大作用域

2.1 ServletContext (上下文对象)

(1)生命周期

  • 创建:服务器启动时,为每个web项目创建一个上下文对象。
  • 销毁:服务器关闭时,或者项目移除时。

(2)作用范围:

  • 项目内共享,当前项目下所有程序都可以共享。

2.2 Request (请求对象)

(1)生命周期

  • 创建:请求开始的时候创建,每个请求都会对应自己的request对象。
  • 销毁:请求结束,响应开始的时候。

(2)作用范围

  • 在一次请求中共享,只在当前请求中有效。

2.3 Session(会话对象)

(1)生命周期

  • 创建:在第一次调用request.getSession()方法时,web容器会检查是否已经有对应的session对象存在,如果没有就创建一个session对象。

  • 销毁

    • 当一段时间内session没有被使用(默认30分钟),被销毁;
    • 服务器非正常关闭(强行关闭)时销毁;
    • 调用session.invalidate()手动销毁。

    注意:服务器正常关闭,再启动,Session对象会进行钝化和活化操作。同时如果服务器钝化的时间在Session 默认销毁时间之内,则活化后Session还是会存在的,否则Session不存在。 如果JavaBean 数据在Session钝化时,没有实现Serializable ,则当Session活化时,会消失。

(2)作用范围

  • 在一次会话中(多次请求)共享数据。

2.4 范围大小

ServletContext > Session > Request

3 Servlet中的8大监听器

3.1 分类

8种Listener如下表所示:

Listener接口 Event类
ServletContextListener ServletContextEvent
ServletContextAttributeListener ServletContextAttributeEvent
HttpSessionListener HttpSessionEvent
HttpSessionActivationListener
HttpSessionAttributeListener HttpSessionBindingEvent
HttpSessionBindingListener
ServletRequestListener ServletRequestEvent
ServletRequestAttributeListener ServletRequestAttributeEvent

分类三类:

  • (1)监听ContextRequestSession对象的创建和销毁,需要在web.xml中配置
    • ServletContextListener
    • ServletRequestListener
    • HttpSessionListener
  • (2)监听ContextRequestSession对象属性的变化,需要在web.xml中配置
    • ServletContextAttributeListener
    • ServletRequestAttributeListener
    • HttpSessionAttributeListener
  • (3)监听Session内部的对象,不需要再web.xml中配置
    • HttpSessionActivationListener
    • HttpSessionBindingListener

3.2 如何使用

  • 实现Listener接口
  • web.xml文件中配置
    • 使用<listener>标签和<listener-class>标签
    • <listener>一般配置在 <servlet>标签的前面
package com.tao.springstarter.web.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

/**
 * 自定义监听器, 实现ServletContextListener
 */
public class MyListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("web容器启动, context对象被创建...");
        System.out.println(sce.getServletContext().toString());
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("web容器关闭, context对象被销毁..."); 
    }
    
}

web.xml

	<!-- 配置监听器 -->
	<listener>
		<listener-class>com.tao.springstarter.web.listener.MyListener</listener-class>
	</listener>

4 详细介绍

4.1 监听ContextRequestSession对象的创建和销毁,需要在web.xml中配置

  • ServletContextListener

  • ServletRequestListener

  • HttpSessionListener

4.1.1 作用和触发时机

(1) ServletContextListener

  • 作用

    • 监听context的创建和销毁,context代表当前的Web应用程序。
    • Listener可用于启动时获取web.xml里面配置的初始化参数。
  • 触发时机

  • 服务器启动或者热部署war包时触发contextInitialized(ServletContextEvent sce)方法。
  • 服务器关闭时或者只关闭该web应用时会触发contextDestroyed(ServletContextEvent sce)方法。

(2)ServletRequestListener

  • 作用

    • 监听request的创建和销毁。
  • 触发时机

    • 用户每次请求request都会触发requestInitialized(ServletRequestEvent sre)方法。
    • request处理完毕自动销毁前触发requestDestroyed(ServletRequestEvent sre)方法。
    • 如果一个HTML页面包含多个图片,则请求一次HTML页面可能会触发多次request事件。

(3)HttpSessionListener

  • 作用

    • 监听Session的创建于销毁。
    • Listener可用于收集在线者信息。
  • 触发时机

    • 创建Session时触发sessionCreated(HttpSessionEvent se)方法。
    • 超时或者执行session.invalidate()方法时执行sessionDestroyed(HttpSessionEvent se)方法。

4.1.2 实例

package com.tao.springstarter.web.listener;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import com.tao.springstarter.entity.JBean;
import com.tao.springstarter.entity.PBean;

/**
 * 自定义监听器, 实现ServletContextListener
 */
public class MyListener implements ServletContextListener, ServletRequestListener, HttpSessionListener {

    // ====================== context ==========================
    // 加载 context
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("web容器启动, context对象被创建...");
        // 可以获取 context对象
        ServletContext context = sce.getServletContext();
        System.out.println("即将启动 " + context.getContextPath());
    }

    // 卸载 context
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("web容器关闭, context对象被销毁...");
        // 可以获取 context对象
        ServletContext context = sce.getServletContext();
        System.out.println("即将关闭 " + context.getContextPath());
    }

    // ====================== request ==========================
    // 创建 request
    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        // 可以获取request对象
        HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
        String uri = request.getRequestURI();
        uri = request.getQueryString() == null ? uri : (uri + "?" + request.getQueryString());
        System.out.println("请求的uri为:" + uri);
        // 可以向request对象中放入这次请求中共享的数据
        request.setAttribute("startTime", System.currentTimeMillis());
    }

    // 销毁 request
    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        // 可以获取request对象, 获取request对象中的共享数据
        HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
        long costTime = System.currentTimeMillis() - (Long) request.getAttribute("startTime");
        System.out.println("本次请求耗时:" + costTime + " ms");
    }

    // ====================== session ==========================
    // 创建 session
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        // 可以获取session对象
        HttpSession session = se.getSession();
        System.out.println("新创建一个session, id = " + session.getId());
        // 向session中添加属性
        session.setAttribute("username", "michael");
        session.setAttribute("jBean", new JBean("JBean1"));
        session.setAttribute("pBean", new PBean("PBean1"));
        // 修改session中的属性
        session.setAttribute("username", "Tom");
        // 删除session中的属性
        session.removeAttribute("username");
        session.removeAttribute("jBean");
    }

    // 销毁 session
    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        // 可以获取session对象
        HttpSession session = se.getSession();
        System.out.println("销毁一个session, id = " + session.getId());
    }

}

4.2 监听ContextRequestSession对象属性的变化,需要在web.xml中配置

  • ServletContextAttributeListener
  • ServletRequestAttributeListener
  • HttpSessionAttributeListener

4.2.1 触发时机

  • 当向被监听对象中添加、更新、移除属性时,会分别执行attributeAdded()attributeReplaced()attributeRemoved()方法。

4.2.2 实例

package com.tao.springstarter.web.listener;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

/**
 * 自定义session属性监听器
 */
public class MySessionAttributeListener implements HttpSessionAttributeListener {

    // 向session中添加属性时触发
    @Override
    public void attributeAdded(HttpSessionBindingEvent event) {
        HttpSession session = event.getSession();
        String key = event.getName();
        Object value = event.getValue();
        System.out.println("向id = " + session.getId() + " 的session中添加的属性为 <" + key + "," + value + ">");
    }

    // 从session中移除属性时触发
    @Override
    public void attributeRemoved(HttpSessionBindingEvent event) {
        HttpSession session = event.getSession();
        String key = event.getName();
        Object value = event.getValue();
        System.out.println("从id = " + session.getId() + " 的session中移除的属性为 <" + key + "," + value + ">");
    }

    // 修改session中属性时触发
    @Override
    public void attributeReplaced(HttpSessionBindingEvent event) {
        HttpSession session = event.getSession();
        String key = event.getName();
        System.out.println("修改id = " + session.getId() + " 的session的属性为  key = " + key);
    }

}

4.3 监听Session内部的对象,不需要再web.xml中配置

保存在Session域中的对象可以有多种状态:

  • 绑定到Session中,session.setAttribute("bean",Object)

  • Session域中解除绑定,session.removeAttribute("bean")

  • Session对象持久化到一个存储设备中

  • Session对象从一个存储设备中恢复

Servlet规范中定义了两个特殊的监听器接口HttpSessionBindingListenerHttpSessionActivationListener来帮助JavaBean 对象了解自己在Session域中的这些状态,实现这两个接口的对象类不需要在web.xml 文件中进行注册

4.3.1 HttpSessionBindingListener

  • 实现了HttpSessionBindingListener接口的JavaBean对象可以感知自己被绑定到Session中和从Session中删除的事件
  • 当对象被绑定到HttpSession对象中时,web服务器调用该对象的valueBound(HttpSessionBindingEvent event)方法
  • 当对象从HttpSession对象中解除绑定时,web服务器调用该对象的valueUnbound(HttpSessionBindingEvent event)方法

4.3.2 HttpSessionActivationListener

  • 实现了HttpSessionActivationListener接口的JavaBean对象可以感知自己被活化(反序列化)和钝化(序列化)的事件
  • 当绑定到HttpSession对象中的JavaBean对象将要随HttpSession对象被钝化**(序列化)**之前,web服务器调用该JavaBean对象的sessionWillPassivate(HttpSessionEvent event) 方法。这样JavaBean对象就可以知道自己将要和HttpSession对象一起被序列化(钝化)到硬盘中。
  • 当绑定到HttpSession对象中的JavaBean对象将要随HttpSession对象被活化**(反序列化)**之后,web服务器调用该JavaBean对象的sessionDidActive(HttpSessionEvent event)方法。这样JavaBean对象就可以知道自己将要和HttpSession对象一起被反序列化(活化)回到内存中。

4.3.3 实例

(1)实现HttpSessionBindingListener 接口

package com.tao.springstarter.entity;

import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

/**
 * 实现了HttpSessionBindingListener的类的对象能够感知被添加到session中和从session中移除的事件
 */
public class JBean implements HttpSessionBindingListener {

    private String name;

    public JBean(String name) {
        this.name = name;
    }

    // JavaBean被加到session中触发
    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        System.out.println(name + "被加到session中了...");
    }

    // 从session中移除JavaBean时触发
    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        System.out.println(name + "从session中被移除了...");
    }

}

上述的JBean这个JavaBean实现了HttpSessionBindingListener接口,那么这个JavaBean对象可以感知自己被绑定到Session中和从Session中删除的这两个操作。

(2)实现HttpSessionActivationListener接口

package com.tao.springstarter.entity;

import java.io.Serializable;

import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;

/**
 * 实现HttpSessionActivationListener接口的JavaBean, 能够感知随session钝化和活化事件
 */
public class PBean implements HttpSessionActivationListener, Serializable {

    private static final long serialVersionUID = 1L;

    private String name;
    
    public PBean(String name) {
        this.name = name;
    }
    
    // 钝化前触发
    @Override
    public void sessionWillPassivate(HttpSessionEvent se) {
        System.out.println(name + "将要和session一起被序列化(钝化)到硬盘, session id = "+se.getSession().getId());
    }

    // 活化后触发
    @Override
    public void sessionDidActivate(HttpSessionEvent se) {
        System.out.println(name + "和session一起从硬盘反序列化(活化)回到内存了, session id = "+se.getSession().getId());
    }

}

5 参考

https://blog.csdn.net/u012228718/article/details/41730799

https://www.cnblogs.com/xdp-gacl/p/3969249.html

发布了178 篇原创文章 · 获赞 152 · 访问量 61万+

猜你喜欢

转载自blog.csdn.net/hbtj_1216/article/details/83015670