一、Listener(监听器)
作用:在 Servlet 规范中,Listener 用于监听 Servlet 容器中的事件(如 ServletContext、HttpSession 和 ServletRequest 的创建与销毁),并在事件发生时执行相应逻辑。
配置方式(web.xml 中):
<listener>
<listener-class>com.example.MyServletContextListener</listener-class>
</listener>
常用监听器接口
-
ServletContextListener
- 监听应用启动/关闭
- 方法:
contextInitialized()
、contextDestroyed()
-
HttpSessionListener
- 监听 Session 创建/销毁
- 方法:
sessionCreated()
、sessionDestroyed()
-
ServletRequestListener
- 监听请求开始/结束
- 方法:
requestInitialized()
、requestDestroyed()
实现原理
- 事件驱动模型:
- 容器(如 Tomcat)在特定生命周期节点(如应用启动时)自动触发事件。
- 反射实例化:
- 容器通过
<listener-class>
反射创建监听器实例。
- 容器通过
- 回调方法:
- 容器直接调用监听器的接口方法(如
contextInitialized()
)。
- 容器直接调用监听器的接口方法(如
- 执行顺序:
- 按
web.xml
中定义的顺序执行。
- 按
示例代码:
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("应用启动!加载数据库连接池...");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("应用关闭!释放资源...");
}
}
二、Filter(过滤器)
作用:拦截请求/响应,在 Servlet/JSP 执行前后添加处理逻辑(如权限验证、日志记录)。
配置方式(web.xml 中):
<filter>
<filter-name>AuthFilter</filter-name>
<filter-class>com.example.AuthFilter</filter-class>
<!-- 可选:初始化参数 -->
<init-param>
<param-name>blockedIPs</param-name>
<param-value>192.168.1.1,10.0.0.2</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>AuthFilter</filter-name>
<url-pattern>/admin/*</url-pattern> <!-- 拦截路径 -->
<dispatcher>REQUEST</dispatcher> <!-- 拦截类型(默认REQUEST) -->
</filter-mapping>
核心接口:javax.servlet.Filter
init()
: 初始化时调用(配置<init-param>
参数)doFilter()
: 拦截请求的核心逻辑destroy()
: 过滤器销毁时调用
实现原理
- 责任链模式:
- 多个过滤器组成链式结构,依次传递请求。
- 拦截流程:
- 用户请求 → 匹配
<url-pattern>
→ 按顺序调用过滤器链 → 到达目标 Servlet/JSP → 响应逆向返回。
- 用户请求 → 匹配
- 关键对象:
FilterChain
:调用chain.doFilter()
将请求传递到下一环节。
- 控制权转移:
- 在
doFilter()
中,chain.doFilter()
前的代码在 Servlet 执行前运行,之后的代码在 Servlet 执行后运行。
- 在
执行顺序:按 <filter-mapping>
在 web.xml
中的定义顺序执行。
示例代码:
public class AuthFilter implements Filter {
public void init(FilterConfig config) {
String ips = config.getInitParameter("blockedIPs");
System.out.println("初始化过滤器,屏蔽IP:" + ips);
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// 1. 前置处理:权限校验
if (userNotLoggedIn()) {
response.sendRedirect("/login");
return;
}
// 2. 放行请求
chain.doFilter(request, response);
// 3. 后置处理:记录日志
System.out.println("请求处理完成,记录操作日志...");
}
}
三、高级特性与对比
特性 | Listener | Filter |
---|---|---|
主要用途 | 响应生命周期事件 | 拦截并处理请求/响应 |
执行时机 | 事件触发时(如应用启动) | 请求到达 Servlet 前/响应返回前 |
配置顺序 | 按 <listener> 声明顺序执行 | 按 <filter-mapping> 顺序执行 |
共享数据 | 通过 ServletContext 存储全局数据 | 通过 request/session 传递数据 |
是否阻断请求 | 否(仅事件响应) | 是(可通过 return 中断流程) |
其他重要细节
-
<dispatcher>
类型(Filter 专属):REQUEST
:直接请求(默认)FORWARD
:转发请求(RequestDispatcher.forward()
)INCLUDE
:包含请求(RequestDispatcher.include()
)ERROR
:错误页面跳转
-
注解替代方案(Servlet 3.0+):
@WebListener // 替代 <listener>
public class MyListener implements ServletContextListener { ... }
@WebFilter(urlPatterns = "/secure/*") // 替代 <filter>
public class SecurityFilter implements Filter { ... }
四、典型应用场景
-
Listener:
- 应用启动时加载缓存/配置文件
- 统计在线用户数(通过
HttpSessionListener
) - 资源清理(如关闭线程池)
-
Filter:
- 统一设置字符编码(
request.setCharacterEncoding("UTF-8")
) - 防止 XSS 攻击(过滤请求参数中的恶意脚本)
- 权限控制(检查 Session 中的用户信息)
- 统一设置字符编码(
注意:在微服务架构中,部分功能(如鉴权、日志)可迁移到网关层(如 Spring Cloud Gateway),但 Listener/Filter 仍是传统 Java Web 应用的核心组件。
五、关键注意事项
1. Listener注意事项
- 初始化顺序:Listener优先于Servlet和Filter初始化,适合加载全局资源。
- 线程安全:实现类需保证线程安全(如使用ThreadLocal或避免共享可变状态)。
- 资源释放:在
contextDestroyed
中正确释放资源(如关闭数据库连接池)。
2. Filter注意事项
- 拦截路径规则:
/*
:拦截所有请求(包括JSP、Servlet、静态资源)。*.jsp
:仅拦截JSP文件。/admin/*
:拦截指定目录。
- 性能影响:避免在Filter中执行耗时操作(如复杂计算或远程调用)。
- 请求放行:必须调用
chain.doFilter()
,否则请求将被中断。
3. 通用最佳实践
- XML结构规范:Listener配置需位于Servlet和Filter之前,遵循DTD/Schema定义。
- 日志记录:在关键节点(如初始化、销毁、拦截)添加日志便于调试。
- 版本兼容性:确保web.xml声明符合Servlet规范版本(如2.5+支持
<filter>
)。
六、总结
Listener和Filter作为Java Web的核心组件,分别通过事件驱动和责任链模式实现应用生命周期管理和请求处理拦截。合理配置二者可显著提升代码可维护性和系统扩展性,但需严格遵循实现规范以避免性能瓶颈和线程安全问题。