0%

监听器

Servlet 监听器(Listener):Web 应用的事件响应机制

监听器(Listener)是 Servlet 规范中用于监听 Web 应用中关键对象(如 ServletContextHttpSessionServletRequest)的创建、销毁及属性变化的组件。它基于事件驱动模型,当特定事件触发时自动执行预设逻辑,常用于初始化资源、监控会话状态、记录请求日志等场景。本文将系统解析监听器的类型、使用方式及典型应用。

监听器的核心概念

什么是监听器?

监听器是实现了特定事件接口的 Java 类,通过监听 Web 应用中的域对象ServletContextHttpSessionServletRequest)或属性变化,在事件发生时执行回调方法。其核心作用是:

  • 感知对象生命周期(创建 / 销毁);
  • 监控对象属性变更(添加 / 移除 / 替换);
  • 实现跨组件通信或资源初始化。

事件与监听器的关系

  • 事件源:触发事件的对象(如 ServletContextHttpSession);
  • 事件对象:封装事件源及相关信息(如 ServletContextEventHttpSessionEvent);
  • 监听器:监听事件并处理(如 ServletContextListenerHttpSessionListener)。

当事件源发生状态变化(如创建、属性修改)时,容器会创建对应的事件对象,并调用注册的监听器的回调方法。

监听器的分类与核心接口

Servlet 规范定义了多种监听器接口,按监听对象可分为三类:域对象生命周期监听器域对象属性监听器会话相关监听器

域对象生命周期监听器

监听 ServletContextHttpSessionServletRequest 的创建与销毁。

监听器接口 事件对象 核心方法 触发时机
ServletContextListener ServletContextEvent contextInitialized() contextDestroyed() Web 应用启动 / 关闭时
HttpSessionListener HttpSessionEvent sessionCreated() sessionDestroyed() 会话创建(首次调用 getSession())/ 销毁(超时或 invalidate()
ServletRequestListener ServletRequestEvent requestInitialized() requestDestroyed() 请求创建(客户端发起请求)/ 销毁(响应完成)
示例:ServletContextListener 初始化资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 监听Web应用启动与关闭,初始化数据库连接池
public class AppInitListener implements ServletContextListener {
private DataSource dataSource;

@Override
public void contextInitialized(ServletContextEvent event) {
// Web应用启动时执行:初始化连接池
dataSource = new BasicDataSource();
// 配置连接池参数...
// 将连接池存入ServletContext,供全局使用
ServletContext context = event.getServletContext();
context.setAttribute("dataSource", dataSource);
System.out.println("应用初始化完成,连接池已创建");
}

@Override
public void contextDestroyed(ServletContextEvent event) {
// Web应用关闭时执行:销毁连接池
if (dataSource != null) {
try {
((BasicDataSource) dataSource).close();
} catch (SQLException e) {
e.printStackTrace();
}
}
System.out.println("应用销毁,连接池已关闭");
}
}

域对象属性监听器

监听域对象中属性的添加、移除或替换。

监听器接口 事件对象 核心方法
ServletContextAttributeListener ServletContextAttributeEvent attributeAdded() attributeRemoved() attributeReplaced()
HttpSessionAttributeListener HttpSessionBindingEvent 同上
ServletRequestAttributeListener ServletRequestAttributeEvent 同上
示例:监控 Session 属性变化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 监听Session中属性的添加、移除、替换
public class SessionAttrListener implements HttpSessionAttributeListener {
@Override
public void attributeAdded(HttpSessionBindingEvent event) {
String attrName = event.getName();
Object value = event.getValue();
System.out.println("Session添加属性:" + attrName + " = " + value);
}

@Override
public void attributeRemoved(HttpSessionBindingEvent event) {
System.out.println("Session移除属性:" + event.getName());
}

@Override
public void attributeReplaced(HttpSessionBindingEvent event) {
String attrName = event.getName();
Object oldValue = event.getValue(); // 旧值
Object newValue = event.getSession().getAttribute(attrName); // 新值
System.out.println("Session替换属性:" + attrName + "(旧:" + oldValue + ",新:" + newValue + ")");
}
}

会话相关监听器

感知会话中对象的绑定、钝化 / 活化等状态变化,无需在 web.xml 中注册。

监听器接口 核心方法 作用描述
HttpSessionBindingListener valueBound() valueUnbound() 当对象被绑定到 Session 或从 Session 解绑时触发
HttpSessionActivationListener sessionWillPassivate() sessionDidActivate() 当 Session 被钝化(写入磁盘)或活化(从磁盘加载)时触发

session会被存储在tomcat当前项目下 .cer文件

示例:HttpSessionBindingListener 感知对象绑定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 用户类:感知自己是否被绑定到Session
public class User implements HttpSessionBindingListener {
private String username;

public User(String username) {
this.username = username;
}

@Override
public void valueBound(HttpSessionBindingEvent event) {
System.out.println("用户 " + username + " 被绑定到Session");
}

@Override
public void valueUnbound(HttpSessionBindingEvent event) {
System.out.println("用户 " + username + " 从Session解绑");
}
}

// 使用:将User对象存入Session时触发valueBound()
HttpSession session = request.getSession();
session.setAttribute("currentUser", new User("zhangsan")); // 触发valueBound()

监听器的配置方式

监听器需注册到 Servlet 容器才能生效,配置方式有两种:

XML 配置(web.xml

1
2
3
4
5
6
7
<!-- 注册监听器,顺序不影响执行(除特殊情况外) -->
<listener>
<listener-class>com.example.AppInitListener</listener-class>
</listener>
<listener>
<listener-class>com.example.SessionAttrListener</listener-class>
</listener>

注意:ServletContextListenercontextInitialized() 会在 Filter 和 Servlet 的 init() 之前执行,保证资源优先初始化。

注解配置(Servlet 3.0+)

直接在监听器类上添加 @WebListener 注解:

1
2
3
4
@WebListener
public class AppInitListener implements ServletContextListener {
// 实现方法...
}

监听器的典型应用场景

  1. 应用初始化
    通过 ServletContextListener 在 Web 应用启动时初始化全局资源(如数据库连接池、Spring IOC 容器、加载配置文件),在关闭时释放资源。
  2. 会话监控
    通过 HttpSessionListener 统计在线用户数量(sessionCreated() 加 1,sessionDestroyed() 减 1)。
  3. 请求日志
    通过 ServletRequestListener 记录每个请求的 URL、访问时间、客户端 IP 等信息,用于审计或性能分析。
  4. 对象持久化
    通过 HttpSessionActivationListener 处理 Session 钝化 / 活化(如 Tomcat 重启时保存会话数据到磁盘,恢复时重新加载)。
  5. 属性变更通知
    通过属性监听器监控关键属性变化(如配置修改),实时触发相应逻辑(如刷新缓存)。

注意事项

  1. 执行顺序
    • 多个 ServletContextListenercontextInitialized() 执行顺序与注册顺序一致,contextDestroyed() 则相反。
    • 其他监听器的执行顺序未明确规定,避免依赖顺序逻辑。
  2. 性能影响
    • 监听器会拦截每一次事件(如每个请求、每个属性修改),避免在回调方法中执行耗时操作(如复杂计算、网络请求)。
  3. 会话钝化 / 活化
    • 实现 HttpSessionActivationListener 的类需实现 Serializable 接口,否则对象无法被序列化到磁盘。
  4. 资源共享
    • 全局资源(如连接池)建议存入 ServletContext,通过 getAttribute() 在整个应用中共享。

欢迎关注我的其它发布渠道

表情 | 预览
快来做第一个评论的人吧~
Powered By Valine
v1.3.10