Java Servlet监听器实操案例
我将通过一个完整的在线用户统计案例,演示三种常用监听器的实操方法。

项目结构
webapp/
├── WEB-INF/
│ └── web.xml
├── index.jsp
└── login.jsp
创建监听器类
1 统计在线用户 - ServletContextListener
package com.example.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class OnlineUserListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("=== 应用启动 ===");
// 初始化在线用户计数器
sce.getServletContext().setAttribute("onlineCount", 0);
sce.getServletContext().setAttribute("userList", new java.util.ArrayList<String>());
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("=== 应用关闭 ===");
// 清理资源
sce.getServletContext().removeAttribute("onlineCount");
sce.getServletContext().removeAttribute("userList");
}
}
2 监听Session创建/销毁 - HttpSessionListener
package com.example.listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
@WebListener
public class SessionTrackerListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("创建Session: " + se.getSession().getId());
// 更新在线用户数
javax.servlet.http.HttpSession session = se.getSession();
javax.servlet.ServletContext context = session.getServletContext();
synchronized (this) {
Integer count = (Integer) context.getAttribute("onlineCount");
context.setAttribute("onlineCount", (count == null ? 0 : count) + 1);
}
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("销毁Session: " + se.getSession().getId());
// 移除用户并更新计数
javax.servlet.http.HttpSession session = se.getSession();
javax.servlet.ServletContext context = session.getServletContext();
synchronized (this) {
// 移除用户
java.util.ArrayList<String> userList =
(java.util.ArrayList<String>) context.getAttribute("userList");
String username = (String) session.getAttribute("username");
if (username != null && userList != null) {
userList.remove(username);
}
// 更新计数
Integer count = (Integer) context.getAttribute("onlineCount");
context.setAttribute("onlineCount", (count == null ? 0 : count) - 1);
}
}
}
3 监听属性变化 - ServletRequestAttributeListener
package com.example.listener;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class RequestLoggerListener implements ServletRequestAttributeListener {
@Override
public void attributeAdded(ServletRequestAttributeEvent srae) {
System.out.println("添加属性: " + srae.getName() +
" = " + srae.getValue());
}
@Override
public void attributeRemoved(ServletRequestAttributeEvent srae) {
System.out.println("移除属性: " + srae.getName() +
" = " + srae.getValue());
}
@Override
public void attributeReplaced(ServletRequestAttributeEvent srae) {
System.out.println("替换属性: " + srae.getName() +
" 旧值: " + srae.getValue() +
" 新值: " + srae.getServletRequest().getAttribute(srae.getName()));
}
}
创建测试用Servlet
package com.example.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String username = req.getParameter("username");
String action = req.getParameter("action");
if ("login".equals(action)) {
// 模拟登录
req.getSession().setAttribute("username", username);
// 添加到在线用户列表
java.util.ArrayList<String> userList =
(java.util.ArrayList<String>) getServletContext().getAttribute("userList");
if (userList != null && !userList.contains(username)) {
userList.add(username);
}
resp.sendRedirect("index.jsp");
} else if ("logout".equals(action)) {
// 模拟登出
req.getSession().invalidate();
resp.sendRedirect("login.jsp");
}
}
}
创建JSP页面
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>登录页面</title>
</head>
<body>
<h2>登录</h2>
<form action="login" method="post">
<input type="hidden" name="action" value="login">
用户名:<input type="text" name="username"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="java.util.ArrayList" %>
<html>
<head>首页</title>
</head>
<body>
<h2>欢迎, ${sessionScope.username}</h2>
<p>当前在线用户数:${applicationScope.onlineCount}</p>
<h3>在线用户列表:</h3>
<ul>
<%
ArrayList<String> userList =
(ArrayList<String>) application.getAttribute("userList");
if (userList != null) {
for (String user : userList) {
%>
<li><%= user %></li>
<%
}
}
%>
</ul>
<form action="login" method="post">
<input type="hidden" name="action" value="logout">
<input type="submit" value="退出登录">
</form>
</body>
</html>
web.xml配置(可选)
如果使用了@WebListener注解,可以省略web.xml配置,但也可以使用XML方式:
<?xml version="1.0" encoding="UTF-8"?>
<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">
<display-name>Listener Demo</display-name>
<!-- 注册监听器 -->
<listener>
<listener-class>com.example.listener.OnlineUserListener</listener-class>
</listener>
<listener>
<listener-class>com.example.listener.SessionTrackerListener</listener-class>
</listener>
<listener>
<listener-class>com.example.listener.RequestLoggerListener</listener-class>
</listener>
<!-- 配置servlet -->
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.example.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
</web-app>
运行测试
- 部署应用到Tomcat等Servlet容器
- 访问
http://localhost:8080/your-app/login.jsp - 输入用户名登录
- 打开多个浏览器窗口登录不同用户
- 观察控制台输出
- 点击退出查看在线用户数变化
常用监听器类型总结
| 监听器类型 | 监听事件 | 适用场景 |
|---|---|---|
| ServletContextListener | 应用启动/关闭 | 初始化资源、加载配置 |
| HttpSessionListener | Session创建/销毁 | 在线用户统计 |
| ServletRequestListener | 请求开始/结束 | 请求日志记录 |
| ServletContextAttributeListener | 应用属性变化 | 监控全局配置变更 |
| HttpSessionAttributeListener | Session属性变化 | 用户登录/登出监控 |
| ServletRequestAttributeListener | 请求属性变化 | 请求处理调试 |
注意事项
- 线程安全:监听器在多线程环境下运行,注意使用同步
- 内存泄漏:避免在监听器中持有强引用导致内存泄漏
- 性能影响:监听器应快速执行,避免阻塞操作
- 使用注解:Servlet 3.0+ 推荐使用@WebListener注解简化配置
这个案例演示了如何通过监听器实时监控用户登录/登出行为,是实际项目中常见的应用场景。