Spring Boot拦截器 vs 过滤器:核心区别与实战指南(附场景对比)

336 阅读3分钟

一、核心定位差异(架构层面对比)

1.1 过滤器(Filter)—— Servlet规范守卫者

  • 所属规范:Java EE标准组件
  • 作用位置:Web容器层面(Tomcat/Jetty)
  • 拦截范围:所有HTTP请求(包括静态资源)
  • 典型场景
    // 示例:字符编码过滤器
    public class CharsetFilter implements Filter {
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
            req.setCharacterEncoding("UTF-8");
            chain.doFilter(req, res); // 必须调用
        }
    }
    

1.2 拦截器(Interceptor)—— Spring MVC的管家

  • 所属框架:Spring MVC特有组件
  • 作用位置:DispatcherServlet之后
  • 拦截范围:Controller请求(不拦截静态资源)
  • 典型场景
    @Component
    public class AuthInterceptor implements HandlerInterceptor {
        public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
            // 权限校验逻辑
            return true; // 放行请求
        }
    }
    

二、执行流程全景图(重点!)

2.1 完整请求生命周期

sequenceDiagram
    participant Client
    participant FilterChain
    participant DispatcherServlet
    participant Interceptor
    participant Controller

    Client->>FilterChain: 请求进入
    FilterChain->>DispatcherServlet: 预处理完成
    DispatcherServlet->>Interceptor: preHandle()
    Interceptor->>Controller: 执行业务逻辑
    Controller->>Interceptor: postHandle()
    Interceptor->>FilterChain: 返回响应
    FilterChain->>Client: 最终响应

2.2 关键顺序对比表

阶段过滤器执行拦截器执行
静态资源访问
进入DispatcherServlet前
Controller方法执行前
视图渲染前
响应返回前

三、6大核心区别详解

3.1 依赖注入支持对比

// 过滤器无法直接使用@Autowired
public class BadFilter implements Filter {
    @Autowired // 这里会注入失败!
    private AuthService authService; 
}

// 拦截器支持Spring注入
@Component
public class GoodInterceptor implements HandlerInterceptor {
    @Autowired // 正常注入
    private AuthService authService;
}

解决方案
通过FilterRegistrationBean包装过滤器:

@Bean
public FilterRegistrationBean<AuthFilter> authFilter(AuthService service) {
    FilterRegistrationBean<AuthFilter> bean = new FilterRegistrationBean<>();
    bean.setFilter(new AuthFilter(service)); // 手动注入
    bean.addUrlPatterns("/*");
    return bean;
}

3.2 配置方式对比

过滤器配置

// 方式1:注解配置(需启动类加@ServletComponentScan)
@WebFilter(urlPatterns = "/*")
public class LogFilter implements Filter {}

// 方式2:JavaConfig显式注册
@Bean
public FilterRegistrationBean<LogFilter> loggingFilter() {
    FilterRegistrationBean<LogFilter> bean = new FilterRegistrationBean<>();
    bean.setFilter(new LogFilter());
    bean.setOrder(1); // 控制执行顺序
    return bean;
}

拦截器配置

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Autowired
    private AuthInterceptor authInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor)
                .addPathPatterns("/api/**")
                .excludePathPatterns("/api/login");
    }
}

3.3 异常处理差异

场景过滤器中的异常拦截器中的异常
能否被@ControllerAdvice捕获
处理建议自行try-catch可抛给全局处理器

四、实战场景选型指南

4.1 必须使用过滤器的场景

  1. 全局字符编码设置
    public class EncodingFilter implements Filter {
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
            req.setCharacterEncoding("UTF-8");
            res.setContentType("application/json;charset=UTF-8");
            chain.doFilter(req, res);
        }
    }
    
  2. 敏感词过滤
    public class SensitiveFilter implements Filter {
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
            CustomRequestWrapper wrappedRequest = new CustomRequestWrapper((HttpServletRequest) req);
            chain.doFilter(wrappedRequest, res);
        }
    }
    

4.2 优先使用拦截器的场景

  1. 接口权限校验
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
        String token = req.getHeader("Authorization");
        if(!authService.validateToken(token)) {
            res.sendError(401, "Invalid token");
            return false;
        }
        return true;
    }
    
  2. 接口耗时监控
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
        req.setAttribute("startTime", System.currentTimeMillis());
        return true;
    }
    
    public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex) {
        long duration = System.currentTimeMillis() - (Long)req.getAttribute("startTime");
        log.info("请求 {} 耗时 {}ms", req.getRequestURI(), duration);
    }
    

五、高级技巧:实现执行顺序控制

5.1 过滤器顺序控制

@Bean
public FilterRegistrationBean<FilterA> filterA() {
    FilterRegistrationBean<FilterA> bean = new FilterRegistrationBean<>();
    bean.setFilter(new FilterA());
    bean.setOrder(Ordered.HIGHEST_PRECEDENCE); // 最高优先级
    return bean;
}

@Bean 
public FilterRegistrationBean<FilterB> filterB() {
    FilterRegistrationBean<FilterB> bean = new FilterRegistrationBean<>();
    bean.setFilter(new FilterB());
    bean.setOrder(Ordered.LOWEST_PRECEDENCE); // 最低优先级
    return bean;
}

5.2 拦截器顺序控制

registry.addInterceptor(new Interceptor1()).order(1);
registry.addInterceptor(new Interceptor2()).order(2); 
// 数字越小优先级越高

六、常见问题排查指南

6.1 过滤器不生效怎么办?

  1. 检查是否添加了@ServletComponentScan
  2. 确认URL模式是否匹配
  3. 查看FilterRegistrationBean的配置顺序

6.2 拦截器preHandle返回false的后果

  • 后续拦截器不再执行
  • Controller方法不会调用
  • postHandle方法不会触发
  • afterCompletion仍然会执行(仅对已通过preHandle的拦截器)

七、终极对比表(建议收藏)

特性过滤器(Filter)拦截器(Interceptor)
规范依赖Servlet APISpring MVC
作用范围所有请求Controller请求
注入Spring Bean需特殊处理直接支持
执行位置DispatcherServlet之前Controller方法前后
异常处理需自行处理可被全局异常处理器捕获
配置方式web.xml或JavaConfigJavaConfig
访问请求体可修改只能读取
性能影响更高(更底层)较低

最佳实践建议:优先使用拦截器处理业务相关逻辑,仅在需要处理底层HTTP协议时使用过滤器。掌握两者的区别后,可以查看Spring Boot的默认过滤器链(如Spring Security过滤器链)加深理解。