Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现与实战指南
一、核心概念对比
1. 本质区别
维度 | 过滤器(Filter) | 拦截器(Interceptor) |
---|---|---|
规范层级 | Servlet规范(J2EE标准) | Spring MVC框架机制 |
作用范围 | 所有请求(包括静态资源) | 只处理Controller请求 |
依赖关系 | 不依赖Spring容器 | 完全集成Spring IOC容器 |
执行顺序 | 最先执行(在DispatcherServlet之前) | 在DispatcherServlet之后执行 |
异常处理 | 无法直接使用Spring的异常处理机制 | 可以通过@ControllerAdvice统一处理 |
2. 执行流程示意图
HTTP Request
↓
Filter Chain(doFilter)
↓
DispatcherServlet
↓
Interceptor.preHandle
↓
Controller Method
↓
Interceptor.postHandle
↓
View Rendering(如有)
↓
Interceptor.afterCompletion
↓
Filter Chain(返回响应)
二、过滤器(Filter)开发指南
1. 基础实现方式
java
@Component
public class LogFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
long startTime = System.currentTimeMillis();
HttpServletRequest req = (HttpServletRequest) request;
// 前置处理
System.out.println("Request URI: " + req.getRequestURI());
chain.doFilter(request, response); // 放行请求
// 后置处理
long duration = System.currentTimeMillis() - startTime;
System.out.println("Request completed in " + duration + "ms");
}
}
2. 高级配置技巧
java
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<LogFilter> loggingFilter() {
FilterRegistrationBean<LogFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new LogFilter());
registration.addUrlPatterns("/api/*");
registration.setOrder(Ordered.HIGHEST_PRECEDENCE); // 设置优先级
return registration;
}
}
典型应用场景:
- 请求日志记录
- 全局字符编码设置
- 跨域处理(CORS)
- XSS防御过滤
- 请求内容压缩/解压
三、拦截器(Interceptor)开发指南
1. 标准实现模板
java
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (!validateToken(token)) {
response.sendError(401, "Invalid token");
return false; // 中断请求
}
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
// Controller方法执行后,视图渲染前
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
// 请求完全结束后(包括视图渲染)
}
}
2. 注册拦截器配置
java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login", "/public/**");
}
}
典型应用场景:
- 接口权限验证
- 请求参数预处理
- 接口耗时监控
- 敏感操作日志
- 数据绑定前校验
四、核心差异深度解析
1. 执行顺序对比实验
配置多个过滤器和拦截器时的执行顺序:
Filter1 → Filter2 → Interceptor.preHandle
→ Controller
→ Interceptor.postHandle
→ Interceptor.afterCompletion
→ Filter2 → Filter1
2. 异常处理差异
java
// 在过滤器中处理异常
public void doFilter(...) {
try {
chain.doFilter(request, response);
} catch (Exception e) {
response.sendError(500, "Server Error");
}
}
// 在拦截器中处理异常
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public ResponseEntity<?> handleException(Exception e) {
return ResponseEntity.internalServerError().body("Error occurred");
}
}
3. 异步请求处理
java
// 拦截器需实现AsyncHandlerInterceptor
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest request,
HttpServletResponse response,
Object handler) {
// 异步请求的特殊处理
}
五、最佳实践与选型策略
1. 技术选型决策树
是否需要处理静态资源?
├─ 是 → 必须使用Filter
└─ 否 →
是否需要访问Spring Bean?
├─ 是 → 选择Interceptor
└─ 否 →
是否需要最早处理请求?
├─ 是 → 选择Filter
└─ 否 → 根据业务复杂度选择
2. 性能优化建议
- 过滤器:避免在过滤器中做复杂业务逻辑
- 拦截器:preHandle方法尽量轻量化
- 两者都应避免:
- 同步阻塞操作
- 频繁的IO操作
- 大对象的内存操作
3. 常见陷阱规避
- 过滤器 :
- 忘记调用chain.doFilter()导致请求阻塞
- 修改请求参数未使用Wrapper类
- 拦截器 :
- 在postHandle中修改ModelAndView导致NPE
- 异步请求中误用afterCompletion
六、实战案例演示
案例1:接口耗时监控系统
java
// 拦截器实现
public class MetricsInterceptor implements HandlerInterceptor {
private static final ThreadLocal<Long> startTime = new ThreadLocal<>();
@Override
public boolean preHandle(...) {
startTime.set(System.currentTimeMillis());
return true;
}
@Override
public void afterCompletion(...) {
long duration = System.currentTimeMillis() - startTime.get();
metricsService.recordRequestTime(request.getRequestURI(), duration);
startTime.remove();
}
}
案例2:全局防重放攻击过滤器
java
public class ReplayAttackFilter implements Filter {
private Cache<String, Boolean> requestCache =
Caffeine.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).build();
@Override
public void doFilter(...) {
String nonce = request.getHeader("X-Nonce");
if (requestCache.getIfPresent(nonce) != null) {
response.sendError(400, "Duplicate request");
return;
}
requestCache.put(nonce, true);
chain.doFilter(request, response);
}
}
七、扩展知识
1. 与AOP的区别
- AOP :
- 基于代理模式实现
- 可以精确控制到具体方法
- 更适合业务层面的切面处理
- 拦截器 :
- 基于HandlerMapping实现
- 主要针对HTTP请求生命周期
- 更适合Web层通用处理
2. 高级应用场景
- 过滤器链:实现责任链模式
- 拦截器栈:组合多个拦截逻辑
- 动态启用/禁用:结合配置中心实现
总结建议
- 优先使用拦截器处理Web层通用逻辑
- 保留过滤器用于底层请求处理
- 复杂场景可以组合使用两者
- 生产环境务必进行性能压测
通过合理运用过滤器和拦截器,开发者可以构建出高可维护性的Web应用架构。建议结合APM工具(如SkyWalking)监控两者的执行效率,持续优化系统性能。