这是一个非常核心且重要的 Servlet API 组件,理解它对于构建健壮的 Web 应用至关重要。

什么是 Servlet 监听器?
一句话概括:
Servlet 监听器是 Servlet API 中的一类特殊接口,你可以实现这些接口来“监听” Servlet 容器(如 Tomcat、Jetty)的某些事件,当这些事件发生时,容器会自动调用你编写的监听器代码,让你可以在事件发生前后执行特定的逻辑。
打个比方:
想象一下 Servlet 容器是一个大楼。

- ServletContextListener 就像一个大楼的“保安”,当大楼刚建成(启动)时,他会去检查消防设施、登记入住人员(初始化);当大楼要拆除了(关闭)时,他会去关掉水电、清理垃圾(销毁资源)。
- HttpSessionListener 就像一个宴会厅的“迎宾员”,每当有一位新客人(Session 创建)进来,他会记录一下;每当有一位客人离开(Session 销毁),他会检查一下客人是否遗落了物品。
监听器的作用(为什么需要它?)
监听器主要用于在特定的生命周期节点执行初始化或清理工作,常见用途包括:
-
资源初始化与销毁:
- 在 Web 应用启动时,初始化数据库连接池(如 Druid, HikariCP)。
- 在 Web 应用关闭时,关闭连接池,释放所有资源。
- 加载初始化配置文件到内存(如
application.properties)。 - 启动一个后台线程(定时任务、消息队列消费者)。
-
统计信息:
- 统计当前在线用户数(通过监听
HttpSession的创建和销毁)。 - 记录网站的访问日志(可以通过
ServletRequestListener监听每次请求)。
- 统计当前在线用户数(通过监听
-
数据预加载:
(图片来源网络,侵删)- 在应用启动时,从数据库加载一些不常变化但被频繁使用的数据(如字典数据、配置信息)到
ServletContext中,避免每次请求都查询数据库。
- 在应用启动时,从数据库加载一些不常变化但被频繁使用的数据(如字典数据、配置信息)到
核心监听器接口详解
Servlet API 提供了多种监听器接口,它们可以分为三大类:作用域监听和 HTTP 会话监听,还有一个特殊的 ServletRequestListener。
1 ServletContext 作用域监听
ServletContext 代表整个 Web 应用,一个应用只有一个 ServletContext 实例,它的生命周期与 Web 应用相同。
a) ServletContextListener
这是最常用、最重要的监听器。
- 监听事件:
contextInitialized(ServletContextEvent sce): 当 Servlet 容器启动 Web 应用时调用(即ServletContext创建时)。contextDestroyed(ServletContextEvent sce): 当 Servlet 容器关闭 Web 应用时调用(即ServletContext销毁时))。
- 如何使用:
- 创建一个类,实现
ServletContextListener接口。 - 实现两个方法
contextInitialized和contextDestroyed。 - 在类上添加
@WebListener注解,或者在web.xml中进行配置。
- 创建一个类,实现
示例代码:
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
// 使用注解方式注册监听器
@WebListener
public class MyServletContextListener implements ServletContextListener {
// 在 Web 应用启动时调用
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("===== Web 应用启动,ServletContext 初始化... =====");
// 1. 初始化数据库连接池
// DataSource dataSource = initDataSource();
// 2. 加载配置文件
// Properties props = loadProperties();
// 3. 将数据存入 ServletContext,供整个应用共享
// sce.getServletContext().setAttribute("dataSource", dataSource);
System.out.println("===== 初始化完成! =====");
}
// 在 Web 应用关闭时调用
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("===== Web 应用关闭,ServletContext 销毁... =====");
// 1. 关闭数据库连接池
// DataSource dataSource = (DataSource) sce.getServletContext().getAttribute("dataSource");
// dataSource.close();
System.out.println("===== 资源释放完成! =====");
}
}
b) ServletContextAttributeListener
- 监听事件:
attributeAdded(ServletContextAttributeEvent scab): 当向ServletContext中添加属性时调用。attributeRemoved(ServletContextAttributeEvent scab): 当从ServletContext中移除属性时调用。attributeReplaced(ServletContextAttributeEvent scab): 当替换ServletContext中的属性时调用。
2 HttpSession 会话监听
HttpSession 代表一个用户与服务器之间的会话,每个用户会话都有一个独立的 HttpSession 实例。
a) HttpSessionListener
- 监听事件:
sessionCreated(HttpSessionEvent se): 当创建一个新的HttpSession时调用(即用户第一次访问网站并创建了会话)。sessionDestroyed(HttpSessionEvent se): 当销毁一个HttpSession时调用(如调用session.invalidate()、会话超时等)。
示例代码(统计在线人数):
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
@WebListener
public class OnlineUserCounterListener implements HttpSessionListener {
// 使用一个静态变量来记录在线人数
private static int onlineCount = 0;
@Override
public void sessionCreated(HttpSessionEvent se) {
// 会话创建,人数加一
onlineCount++;
System.out.println("新用户上线,当前在线人数: " + onlineCount);
se.getSession().getServletContext().setAttribute("onlineCount", onlineCount);
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
// 会话销毁,人数减一
onlineCount--;
System.out.println("用户下线,当前在线人数: " + onlineCount);
se.getSession().getServletContext().setAttribute("onlineCount", onlineCount);
}
}
b) HttpSessionAttributeListener
- 监听事件:
attributeAdded(HttpSessionBindingEvent se): 当向HttpSession中添加属性时调用。attributeRemoved(HttpSessionBindingEvent se): 当从HttpSession中移除属性时调用。attributeReplaced(HttpSessionBindingEvent se): 当替换HttpSession中的属性时调用。
c) HttpSessionActivationListener 和 HttpSessionIdListener
HttpSessionActivationListener: 监听会话的序列化和反序列化(钝化和活化),用于分布式环境。HttpSessionIdListener: 监听会话 ID 的变化。
3 ServletRequest 请求监听
ServletRequest 代表一个客户端请求。
a) ServletRequestListener
- 监听事件:
requestInitialized(ServletRequestEvent sre): 当每次客户端请求到达时调用。requestDestroyed(ServletRequestEvent sre): 当每次客户端请求处理完毕后调用。
用途: 可以用于记录请求日志、统一设置请求编码等。
b) ServletRequestAttributeListener
- 监听事件:
attributeAdded(...),attributeRemoved(...),attributeReplaced(...): 监听ServletRequest属性的增删改。
如何注册监听器?
有两种方式:注解方式(推荐) 和 web.xml 配置方式。
使用 @WebListener 注解(Java EE 6+ / Servlet 3.0+)
这是最简单、最现代的方式,只需在你实现的监听器类上添加 @WebListener 注解即可。
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionListener;
@WebListener
public class MySessionListener implements HttpSessionListener {
// ...
}
在 web.xml 中配置(传统方式)
如果你的项目还在使用较老的 Servlet 规范,或者需要更复杂的配置,可以在 web.xml 中进行声明。
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 配置 ServletContextListener -->
<listener>
<listener-class>com.example.MyServletContextListener</listener-class>
</listener>
<!-- 配置 HttpSessionListener -->
<listener>
<listener-class>com.example.OnlineUserCounterListener</listener-class>
</listener>
</web-app>
最佳实践与注意事项
- 监听器要轻量: 监听器中的代码应该尽可能快地执行,特别是
contextInitialized方法,如果执行时间过长,会导致 Web 应用启动缓慢,耗时的操作(如加载大量数据)应该异步处理。 - 不要在监听器中处理业务逻辑: 监听器是生命周期管理工具,不是业务逻辑控制器,不要在监听器中直接处理用户的请求或复杂的业务流程。
- 异常处理: 监听器中的异常需要妥善处理。
contextInitialized方法抛出异常会导致整个 Web 应用启动失败。 - 监听器顺序: 如果有多个监听器,它们的执行顺序可以通过
@WebListener的value属性(在web.xml中通过<listener>的顺序)来控制,但在实际开发中,应尽量避免监听器之间有强依赖关系。 - 监听器的移除: 在
contextDestroyed方法中,一定要记得释放所有在contextInitialized中初始化的资源,防止内存泄漏。
| 监听器接口 | 监听对象 | 主要用途 | 核心方法 |
|---|---|---|---|
ServletContextListener |
ServletContext (整个应用) |
应用启动/关闭时的初始化和销毁 | contextInitialized, contextDestroyed |
HttpSessionListener |
HttpSession (用户会话) |
统计在线用户、会话生命周期管理 | sessionCreated, sessionDestroyed |
ServletRequestListener |
ServletRequest (单个请求) |
记录请求日志、统一设置编码 | requestInitialized, requestDestroyed |
...AttributeListener |
对应作用域的属性 | 监听作用域中属性的增删改 | attributeAdded, attributeRemoved, attributeReplaced |
掌握 Servlet 监听器是构建高质量 Java Web 应用的必备技能,它能帮助你更好地管理应用的生命周期和资源。
