文章目录
本文部分内容由 DeepSeek生成
过滤器与拦截器的深度解析
一、本质区别:架构层面的对比
1. 规范与框架层面的差异
过滤器(Filter):
- 属于JavaEE Servlet规范的标准组件
- 由Servlet容器(如Tomcat、Jetty)直接管理
- 不依赖任何Web框架,可在纯Servlet环境中使用
- 工作于Servlet API层面,处理的是
ServletRequest
和ServletResponse
拦截器(Interceptor):
- 是Spring MVC框架的专属组件
- 完全由Spring IoC容器管理生命周期
- 深度集成Spring生态,可访问HandlerMethod等Spring特有对象
- 工作于Spring MVC的DispatcherServlet之后,处理的是
HttpServletRequest
和HttpServletResponse
2. 作用域对比
特性 | 过滤器 | 拦截器 |
---|---|---|
请求类型 | 所有HTTP请求(包括静态资源) | 仅Spring MVC路由的请求 |
作用阶段 | Servlet容器层面 | Spring MVC处理管道 |
控制粒度 | 粗粒度(整个请求/响应) | 细粒度(可精确到Controller方法) |
二、执行顺序:微观层面的流程剖析
完整生命周期流程图
关键顺序特征
-
过滤器链:
- 先进后出(FILO)的执行方式
- 按
FilterRegistrationBean
设置的order顺序执行前置代码 - 按相反顺序执行后置代码
-
拦截器链:
preHandle
:按注册顺序正序执行postHandle
:按注册顺序逆序执行afterCompletion
:按注册顺序逆序执行- 任意
preHandle
返回false会触发已完成拦截器的afterCompletion
三、实现原理:底层机制解析
过滤器实现机制
核心类关系:
FilterRegistrationBean → DelegatingFilterProxy → 实际Filter实现
初始化过程:
- Servlet容器启动时扫描
@WebFilter
或web.xml配置 - Spring Boot通过
FilterRegistrationBean
动态注册 - 通过
DelegatingFilterProxy
桥接Spring管理的Filter
执行流程:
// 伪代码展示FilterChain执行
public void doFilter(ServletRequest req, ServletResponse res) {
if (currentFilter < filters.length) {
filters[currentFilter++].doFilter(req, res, this);
} else {
servlet.service(req, res); // 最终到达Servlet
}
// 执行后续filter的后置代码
}
拦截器实现机制
核心类关系:
HandlerExecutionChain
├── HandlerInterceptor1
├── HandlerInterceptor2
└── HandlerMethod
DispatcherServlet处理流程:
doDispatch()
方法获取HandlerExecutionChain- 按顺序调用
applyPreHandle()
for (int i = 0; i < interceptors.length; i++) { if (!interceptors[i].preHandle()) { triggerAfterCompletion(); // 中断流程 return false; } }
- 执行HandlerAdapter处理
- 逆序调用
applyPostHandle()
for (int i = interceptors.length - 1; i >= 0; i--) { interceptors[i].postHandle(); }
- 视图渲染后触发
triggerAfterCompletion()
四、深度功能对比
1. 请求/响应修改能力
过滤器:
- 可以完全替换请求/响应对象
- 示例:包装请求实现body重复读取
chain.doFilter(new CachedRequestWrapper(request), response);
拦截器:
- 只能修改请求参数或响应内容
- 无法替换底层HttpServletRequest对象
- 示例:添加响应头
response.setHeader("X-Trace-ID", UUID.randomUUID().toString());
2. 异常处理对比
过滤器异常处理:
public void doFilter(...) {
try {
chain.doFilter(req, res);
} catch (Exception e) {
// 处理Servlet容器抛出的异常
response.sendError(500);
}
}
拦截器异常处理:
public void afterCompletion(...) {
if (ex != null) {
// 可以区分不同类型的异常
if (ex instanceof BusinessException) {
logger.warn("业务异常", ex);
}
}
}
3. 性能监控实现差异
过滤器实现监控:
public void doFilter(...) {
long start = System.currentTimeMillis();
try {
chain.doFilter(req, res);
} finally {
long cost = System.currentTimeMillis() - start;
metrics.record("filter.time", cost);
}
}
拦截器实现监控:
public boolean preHandle(...) {
request.setAttribute("startTime", System.nanoTime());
return true;
}
public void afterCompletion(...) {
Long start = (Long)request.getAttribute("startTime");
long cost = System.nanoTime() - start;
metrics.record(handler.toString(), cost);
}
五、高级应用场景
过滤器的典型进阶用法
-
请求解密/响应加密:
public void doFilter(...) { EncryptedRequestWrapper wrappedReq = new EncryptedRequestWrapper(request); EncryptedResponseWrapper wrappedRes = new EncryptedResponseWrapper(response); chain.doFilter(wrappedReq, wrappedRes); byte[] encrypted = encrypt(wrappedRes.getContent()); response.getOutputStream().write(encrypted); }
-
全局缓存控制:
public void doFilter(...) { if (isCacheable(request)) { CachedResponse cached = cache.get(request.getRequestURI()); if (cached != null) { writeCachedResponse(cached, response); return; } } chain.doFilter(req, res); }
拦截器的典型进阶用法
-
权限注解处理:
public boolean preHandle(...) { if (handler instanceof HandlerMethod) { RequiresPermission perm = ((HandlerMethod)handler).getMethodAnnotation(...); if (perm != null && !checkPermission(perm.value())) { throw new AccessDeniedException(); } } return true; }
-
API版本控制:
public boolean preHandle(...) { String version = request.getHeader("X-API-Version"); RequestVersionContext.setVersion(version); return true; } public void afterCompletion(...) { RequestVersionContext.clear(); }
六、配置陷阱与最佳实践
常见配置错误
-
过滤器顺序失控:
// 错误:未指定order导致执行顺序随机 @Bean public FilterRegistrationBean<FilterA> filterA() { return new FilterRegistrationBean<>(new FilterA()); } // 正确做法 @Bean public FilterRegistrationBean<FilterA> filterA() { FilterRegistrationBean<FilterA> bean = new FilterRegistrationBean<>(); bean.setFilter(new FilterA()); bean.setOrder(Ordered.HIGHEST_PRECEDENCE); return bean; }
-
拦截器路径匹配错误:
// 错误:会拦截所有请求包括静态资源 registry.addInterceptor(new AuthInterceptor()).addPathPatterns("/**"); // 正确做法 registry.addInterceptor(new AuthInterceptor()) .addPathPatterns("/api/**") .excludePathPatterns("/static/**", "/error");
性能优化建议
-
过滤器优化:
- 在
init()
方法中初始化重量级资源 - 对静态资源使用
FilterRegistrationBean.setDispatcherTypes(REQUEST)
- 在
-
拦截器优化:
- 使用
@Order
或InterceptorRegistry.order()
精确控制顺序 - 在
preHandle
中尽早返回false中断无效请求
- 使用
七、组合使用策略
典型分层架构
HTTP请求
│
├── 安全过滤器(SecurityFilter) :处理HTTPS重定向、CORS等
├── 日志过滤器(LoggingFilter) :记录请求日志
│
├── DispatcherServlet
│ │
│ ├── 认证拦截器(AuthInterceptor) :JWT校验
│ ├── 权限拦截器(PermissionInterceptor) :注解权限检查
│ │
│ └── Controller方法
│
└── 响应加密过滤器(EncryptFilter) :对敏感数据加密
异常处理协作
// 全局异常处理器
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler
public ResponseEntity<?> handle(Exception ex) {
return ResponseEntity.badRequest().body(...);
}
}
// 过滤器异常处理
public void doFilter(...) {
try {
chain.doFilter(req, res);
} catch (Exception e) {
request.setAttribute("filter.error", e);
request.getRequestDispatcher("/error").forward(req, res);
}
}
// 拦截器异常记录
public void afterCompletion(...) {
if (ex != null) {
auditService.recordError(request, ex);
}
}