过滤器与拦截器学习


本文部分内容由 DeepSeek生成

过滤器与拦截器的深度解析

一、本质区别:架构层面的对比

1. 规范与框架层面的差异

过滤器(Filter)

  • 属于JavaEE Servlet规范的标准组件
  • 由Servlet容器(如Tomcat、Jetty)直接管理
  • 不依赖任何Web框架,可在纯Servlet环境中使用
  • 工作于Servlet API层面,处理的是ServletRequestServletResponse

拦截器(Interceptor)

  • Spring MVC框架的专属组件
  • 完全由Spring IoC容器管理生命周期
  • 深度集成Spring生态,可访问HandlerMethod等Spring特有对象
  • 工作于Spring MVC的DispatcherServlet之后,处理的是HttpServletRequestHttpServletResponse

2. 作用域对比

特性过滤器拦截器
请求类型所有HTTP请求(包括静态资源)仅Spring MVC路由的请求
作用阶段Servlet容器层面Spring MVC处理管道
控制粒度粗粒度(整个请求/响应)细粒度(可精确到Controller方法)
静态资源
API请求
MVC路由
非MVC请求
所有HTTP请求
图片/CSS/JS等
DispatcherServlet
Controller
404/错误页面
过滤器
拦截器

二、执行顺序:微观层面的流程剖析

完整生命周期流程图

Client FilterChain DispatcherServlet InterceptorChain Controller HTTP Request Filter1.doFilter() Filter2.doFilter() loop [过滤器前置- 处理] 进入Servlet容器 开始MVC处理 Interceptor1.preHandle() Interceptor2.preHandle() loop [拦截器前置处理] 执行HandlerMethod 返回ModelAndView Interceptor2.postHandle() Interceptor1.postHandle() loop [拦截器后置处理(逆- 序)] 视图渲染 Interceptor2.afterCompletion() Interceptor1.afterCompletion() loop [拦截器完成处理(逆序)] 返回响应 Filter2.doFilter()后续代码 Filter1.doFilter()后续代码 loop [过滤器后置处理(逆- 序)] HTTP Response Client FilterChain DispatcherServlet InterceptorChain Controller

关键顺序特征

  1. 过滤器链

    • 先进后出(FILO)的执行方式
    • FilterRegistrationBean设置的order顺序执行前置代码
    • 按相反顺序执行后置代码
  2. 拦截器链

    • preHandle:按注册顺序正序执行
    • postHandle:按注册顺序逆序执行
    • afterCompletion:按注册顺序逆序执行
    • 任意preHandle返回false会触发已完成拦截器的afterCompletion

三、实现原理:底层机制解析

过滤器实现机制

核心类关系

FilterRegistrationBean → DelegatingFilterProxy → 实际Filter实现

初始化过程

  1. Servlet容器启动时扫描@WebFilter或web.xml配置
  2. Spring Boot通过FilterRegistrationBean动态注册
  3. 通过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处理流程

  1. doDispatch()方法获取HandlerExecutionChain
  2. 按顺序调用applyPreHandle()
    for (int i = 0; i < interceptors.length; i++) {
        if (!interceptors[i].preHandle()) {
            triggerAfterCompletion(); // 中断流程
            return false;
        }
    }
    
  3. 执行HandlerAdapter处理
  4. 逆序调用applyPostHandle()
    for (int i = interceptors.length - 1; i >= 0; i--) {
        interceptors[i].postHandle();
    }
    
  5. 视图渲染后触发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);
}

五、高级应用场景

过滤器的典型进阶用法

  1. 请求解密/响应加密

    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);
    }
    
  2. 全局缓存控制

    public void doFilter(...) {
        if (isCacheable(request)) {
            CachedResponse cached = cache.get(request.getRequestURI());
            if (cached != null) {
                writeCachedResponse(cached, response);
                return;
            }
        }
        chain.doFilter(req, res);
    }
    

拦截器的典型进阶用法

  1. 权限注解处理

    public boolean preHandle(...) {
        if (handler instanceof HandlerMethod) {
            RequiresPermission perm = ((HandlerMethod)handler).getMethodAnnotation(...);
            if (perm != null && !checkPermission(perm.value())) {
                throw new AccessDeniedException();
            }
        }
        return true;
    }
    
  2. API版本控制

    public boolean preHandle(...) {
        String version = request.getHeader("X-API-Version");
        RequestVersionContext.setVersion(version);
        return true;
    }
    
    public void afterCompletion(...) {
        RequestVersionContext.clear();
    }
    

六、配置陷阱与最佳实践

常见配置错误

  1. 过滤器顺序失控

    // 错误:未指定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;
    }
    
  2. 拦截器路径匹配错误

    // 错误:会拦截所有请求包括静态资源
    registry.addInterceptor(new AuthInterceptor()).addPathPatterns("/**");
    
    // 正确做法
    registry.addInterceptor(new AuthInterceptor())
            .addPathPatterns("/api/**")
            .excludePathPatterns("/static/**", "/error");
    

性能优化建议

  1. 过滤器优化

    • init()方法中初始化重量级资源
    • 对静态资源使用FilterRegistrationBean.setDispatcherTypes(REQUEST)
  2. 拦截器优化

    • 使用@OrderInterceptorRegistry.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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Liwan95

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值