Servlet监听器详解
监听器概述
Servlet监听器(Listener)是Java Web应用中用于监听和响应Web应用生命周期事件以及属性变化事件的组件。监听器允许开发者在特定事件发生时执行自定义代码,实现对Web应用的监控和控制。
监听器的作用
- 生命周期管理:监听Web应用、Session和Request的创建和销毁
- 属性变更监听:监控应用范围、会话范围和请求范围内属性的变化
- 会话管理:监控会话中对象的绑定和解绑
- 异步处理:监听异步处理的开始和结束
- 请求状态监控:监控请求的生命周期
监听器的类型
根据监听的事件类型,Servlet监听器主要分为以下几类:
- ServletContext监听器
- HttpSession监听器
- ServletRequest监听器
- 属性变更监听器
- Session相关的对象绑定监听器
ServletContext监听器
ServletContextListener
作用:监听ServletContext(应用上下文)的创建和销毁。
主要方法:
java
public interface ServletContextListener extends EventListener {
// 当Web应用启动时调用
void contextInitialized(ServletContextEvent sce);
// 当Web应用关闭时调用
void contextDestroyed(ServletContextEvent sce);
}使用示例:
java
import javax.servlet.*;
import javax.servlet.annotation.WebListener;
import java.util.logging.Logger;
@WebListener
public class AppContextListener implements ServletContextListener {
private static final Logger logger = Logger.getLogger(AppContextListener.class.getName());
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext context = sce.getServletContext();
logger.info("Web应用初始化开始");
// 应用初始化操作
// 1. 加载配置文件
String configPath = context.getInitParameter("configPath");
logger.info("配置文件路径: " + configPath);
// 2. 初始化数据库连接池
// initDatabasePool();
// 3. 加载全局缓存数据
// loadCacheData();
// 4. 设置全局属性
context.setAttribute("appStartTime", System.currentTimeMillis());
logger.info("Web应用初始化完成");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
logger.info("Web应用销毁开始");
// 应用销毁前清理操作
// 1. 关闭数据库连接池
// closeDatabasePool();
// 2. 释放其他资源
// releaseResources();
logger.info("Web应用销毁完成");
}
}ServletContextAttributeListener
作用:监听ServletContext范围内属性的添加、删除和替换。
主要方法:
java
public interface ServletContextAttributeListener extends EventListener {
// 当属性添加到ServletContext时调用
void attributeAdded(ServletContextAttributeEvent scae);
// 当属性从ServletContext移除时调用
void attributeRemoved(ServletContextAttributeEvent scae);
// 当ServletContext中的属性被替换时调用
void attributeReplaced(ServletContextAttributeEvent scae);
}使用示例:
java
import javax.servlet.*;
import javax.servlet.annotation.WebListener;
import java.util.logging.Logger;
@WebListener
public class AppContextAttributeListener implements ServletContextAttributeListener {
private static final Logger logger = Logger.getLogger(AppContextAttributeListener.class.getName());
@Override
public void attributeAdded(ServletContextAttributeEvent scae) {
String name = scae.getName();
Object value = scae.getValue();
logger.info("应用属性添加: " + name + " = " + value);
}
@Override
public void attributeRemoved(ServletContextAttributeEvent scae) {
String name = scae.getName();
Object value = scae.getValue();
logger.info("应用属性移除: " + name + " = " + value);
}
@Override
public void attributeReplaced(ServletContextAttributeEvent scae) {
String name = scae.getName();
Object oldValue = scae.getValue();
ServletContext context = scae.getServletContext();
Object newValue = context.getAttribute(name);
logger.info("应用属性替换: " + name + " 从 " + oldValue + " 变为 " + newValue);
}
}HttpSession监听器
HttpSessionListener
作用:监听HTTP会话的创建和销毁。
主要方法:
java
public interface HttpSessionListener extends EventListener {
// 当会话创建时调用
void sessionCreated(HttpSessionEvent se);
// 当会话销毁时调用
void sessionDestroyed(HttpSessionEvent se);
}使用示例:
java
import javax.servlet.*;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
@WebListener
public class SessionListener implements HttpSessionListener {
private static final Logger logger = Logger.getLogger(SessionListener.class.getName());
// 在线用户计数器
private static final AtomicInteger activeUsers = new AtomicInteger(0);
@Override
public void sessionCreated(HttpSessionEvent se) {
HttpSession session = se.getSession();
String sessionId = session.getId();
logger.info("会话创建: " + sessionId);
// 增加在线用户数
int count = activeUsers.incrementAndGet();
logger.info("当前在线用户数: " + count);
// 设置会话超时时间(单位:秒)
session.setMaxInactiveInterval(1800); // 30分钟
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session = se.getSession();
String sessionId = session.getId();
logger.info("会话销毁: " + sessionId);
// 减少在线用户数
int count = activeUsers.decrementAndGet();
logger.info("当前在线用户数: " + count);
// 清理会话中的资源
// 例如:移除绑定到会话的临时文件等
}
// 获取当前在线用户数
public static int getActiveUsersCount() {
return activeUsers.get();
}
}HttpSessionAttributeListener
作用:监听HTTP会话范围内属性的添加、删除和替换。
主要方法:
java
public interface HttpSessionAttributeListener extends EventListener {
// 当属性添加到会话时调用
void attributeAdded(HttpSessionBindingEvent se);
// 当属性从会话移除时调用
void attributeRemoved(HttpSessionBindingEvent se);
// 当会话中的属性被替换时调用
void attributeReplaced(HttpSessionBindingEvent se);
}使用示例:
java
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import java.util.logging.Logger;
@WebListener
public class SessionAttributeListener implements HttpSessionAttributeListener {
private static final Logger logger = Logger.getLogger(SessionAttributeListener.class.getName());
@Override
public void attributeAdded(HttpSessionBindingEvent se) {
String name = se.getName();
Object value = se.getValue();
String sessionId = se.getSession().getId();
logger.info("会话属性添加[" + sessionId + "]: " + name + " = " + value);
// 特别处理用户登录
if ("user".equals(name)) {
logger.info("用户登录: " + value);
// 可以记录登录日志、更新登录状态等
}
}
@Override
public void attributeRemoved(HttpSessionBindingEvent se) {
String name = se.getName();
Object value = se.getValue();
String sessionId = se.getSession().getId();
logger.info("会话属性移除[" + sessionId + "]: " + name + " = " + value);
// 特别处理用户登出
if ("user".equals(name)) {
logger.info("用户登出: " + value);
// 可以记录登出日志、清理用户相关资源等
}
}
@Override
public void attributeReplaced(HttpSessionBindingEvent se) {
String name = se.getName();
Object oldValue = se.getValue();
Object newValue = se.getSession().getAttribute(name);
String sessionId = se.getSession().getId();
logger.info("会话属性替换[" + sessionId + "]: " + name + " 从 " + oldValue + " 变为 " + newValue);
}
}ServletRequest监听器
ServletRequestListener
作用:监听HTTP请求的创建和销毁。
主要方法:
java
public interface ServletRequestListener extends EventListener {
// 当请求创建时调用
void requestInitialized(ServletRequestEvent sre);
// 当请求销毁时调用
void requestDestroyed(ServletRequestEvent sre);
}使用示例:
java
import javax.servlet.*;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
import java.util.logging.Logger;
@WebListener
public class RequestListener implements ServletRequestListener {
private static final Logger logger = Logger.getLogger(RequestListener.class.getName());
@Override
public void requestInitialized(ServletRequestEvent sre) {
HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
String requestURI = request.getRequestURI();
String clientIP = request.getRemoteAddr();
String sessionId = request.getSession().getId();
logger.info("请求初始化: " + requestURI + " from " + clientIP + " (session: " + sessionId + ")");
// 记录请求开始时间,用于计算请求处理时间
long startTime = System.currentTimeMillis();
request.setAttribute("requestStartTime", startTime);
}
@Override
public void requestDestroyed(ServletRequestEvent sre) {
HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
String requestURI = request.getRequestURI();
// 计算请求处理时间
Long startTime = (Long) request.getAttribute("requestStartTime");
if (startTime != null) {
long processTime = System.currentTimeMillis() - startTime;
logger.info("请求销毁: " + requestURI + " 处理时间: " + processTime + "ms");
// 如果处理时间过长,可以记录警告
if (processTime > 1000) { // 超过1秒
logger.warning("请求处理时间过长: " + requestURI + " 耗时: " + processTime + "ms");
}
} else {
logger.info("请求销毁: " + requestURI);
}
// 清理请求中的临时资源
request.removeAttribute("requestStartTime");
}
}ServletRequestAttributeListener
作用:监听HTTP请求范围内属性的添加、删除和替换。
主要方法:
java
public interface ServletRequestAttributeListener extends EventListener {
// 当属性添加到请求时调用
void attributeAdded(ServletRequestAttributeEvent srae);
// 当属性从请求移除时调用
void attributeRemoved(ServletRequestAttributeEvent srae);
// 当请求中的属性被替换时调用
void attributeReplaced(ServletRequestAttributeEvent srae);
}使用示例:
java
import javax.servlet.*;
import javax.servlet.annotation.WebListener;
import java.util.logging.Logger;
@WebListener
public class RequestAttributeListener implements ServletRequestAttributeListener {
private static final Logger logger = Logger.getLogger(RequestAttributeListener.class.getName());
@Override
public void attributeAdded(ServletRequestAttributeEvent srae) {
String name = srae.getName();
Object value = srae.getValue();
logger.info("请求属性添加: " + name + " = " + value);
}
@Override
public void attributeRemoved(ServletRequestAttributeEvent srae) {
String name = srae.getName();
Object value = srae.getValue();
logger.info("请求属性移除: " + name + " = " + value);
}
@Override
public void attributeReplaced(ServletRequestAttributeEvent srae) {
String name = srae.getName();
Object oldValue = srae.getValue();
ServletRequest request = srae.getServletRequest();
Object newValue = request.getAttribute(name);
logger.info("请求属性替换: " + name + " 从 " + oldValue + " 变为 " + newValue);
}
}Session对象绑定监听器
HttpSessionBindingListener
作用:监听对象被绑定到会话或从会话中解绑的事件。
与其他监听器不同,HttpSessionBindingListener是由被绑定的对象实现的,而不是由单独的监听器类实现。这样,当对象被添加到会话或从会话中移除时,对象自身就能感知到。
主要方法:
java
public interface HttpSessionBindingListener extends EventListener {
// 当对象被绑定到会话时调用
void valueBound(HttpSessionBindingEvent event);
// 当对象从会话中解绑时调用
void valueUnbound(HttpSessionBindingEvent event);
}使用示例:
java
import javax.servlet.http.*;
import java.util.logging.Logger;
// 用户类实现HttpSessionBindingListener接口
public class User implements HttpSessionBindingListener {
private static final Logger logger = Logger.getLogger(User.class.getName());
private String username;
private String email;
private String lastLoginIP;
// 构造方法、getter和setter方法
public User(String username, String email, String lastLoginIP) {
this.username = username;
this.email = email;
this.lastLoginIP = lastLoginIP;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getLastLoginIP() {
return lastLoginIP;
}
public void setLastLoginIP(String lastLoginIP) {
this.lastLoginIP = lastLoginIP;
}
@Override
public void valueBound(HttpSessionBindingEvent event) {
HttpSession session = event.getSession();
String sessionId = session.getId();
logger.info("用户" + username + "被绑定到会话" + sessionId);
// 执行用户登录后的操作
// 例如:更新用户登录状态、记录登录日志等
// updateLoginStatus(true);
// logUserLogin();
}
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
HttpSession session = event.getSession();
String sessionId = session.getId();
logger.info("用户" + username + "从会话" + sessionId + "中解绑");
// 执行用户登出后的操作
// 例如:更新用户登出状态、清理用户相关资源等
// updateLoginStatus(false);
// cleanupUserResources();
}
@Override
public String toString() {
return "User{username='" + username + "', email='" + email + "'}";
}
}
// 在Servlet中使用
// User user = new User("admin", "admin@example.com", request.getRemoteAddr());
// session.setAttribute("user", user); // 这里会触发valueBound方法
// session.removeAttribute("user"); // 这里会触发valueUnbound方法HttpSessionActivationListener
作用:监听会话的钝化(序列化到磁盘)和活化(从磁盘加载)事件。
当Web容器需要释放内存时,可能会将会话序列化到磁盘(钝化);当需要再次使用会话时,会从磁盘加载会话(活化)。
主要方法:
java
public interface HttpSessionActivationListener extends EventListener {
// 当会话被活化(从磁盘加载)时调用
void sessionDidActivate(HttpSessionEvent se);
// 当会话被钝化(序列化到磁盘)时调用
void sessionWillPassivate(HttpSessionEvent se);
}使用示例:
java
import javax.servlet.http.*;
import java.io.Serializable;
import java.util.logging.Logger;
// 需要实现Serializable接口,才能被序列化
public class ShoppingCart implements HttpSessionActivationListener, Serializable {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(ShoppingCart.class.getName());
private String cartId;
private java.util.Map<String, Integer> items = new java.util.HashMap<>();
// 构造方法、getter和setter方法
public ShoppingCart(String cartId) {
this.cartId = cartId;
}
public void addItem(String productId, int quantity) {
items.put(productId, quantity);
}
public void removeItem(String productId) {
items.remove(productId);
}
public int getTotalItems() {
return items.size();
}
@Override
public void sessionDidActivate(HttpSessionEvent se) {
HttpSession session = se.getSession();
logger.info("购物车" + cartId + "被活化,会话ID: " + session.getId());
// 会话活化后的初始化操作
// 例如:重新加载关联的数据库数据等
// reloadDataFromDatabase();
}
@Override
public void sessionWillPassivate(HttpSessionEvent se) {
HttpSession session = se.getSession();
logger.info("购物车" + cartId + "将被钝化,会话ID: " + session.getId());
// 会话钝化前的清理操作
// 例如:释放不能序列化的资源等
// releaseNonSerializableResources();
}
@Override
public String toString() {
return "ShoppingCart{cartId='" + cartId + "', items=