Spring拦截器(Interceptor)与过滤器

Spring 拦截器(Interceptor)与过滤器(Filter)全解析(2025 版)

继续 Spring MVC 系列!拦截器和过滤器都是 AOP(面向切面编程)的经典实现,用于处理请求/响应,但执行时机、作用域、功能深度完全不同
Spring Boot 3.x(Spring Framework 6.x)下,配置几乎零门槛,直接复制代码就能用。

一、核心区别对比表(面试/生产必背)

维度Filter(过滤器)Interceptor(拦截器)
所属规范Servlet API(jakarta.servlet.Filter)Spring MVC(org.springframework.web.servlet.HandlerInterceptor)
执行时机最外层:请求到达 Servlet 容器前/响应返回前(DispatcherServlet 前)内层:DispatcherServlet 后,Controller 前/后/完成时
作用范围所有 Servlet/JSP/静态资源(包括 Spring MVC 外)只针对 Spring MVC 的 Handler(Controller 方法)
访问 Spring 容器否(纯 Servlet,不能注入 Bean)是(可注入 Service/Repository 等)
方法doFilter()preHandle() / postHandle() / afterCompletion()
顺序控制web.xml 或 @Order / FilterRegistrationBean注册顺序或 @Order
异常处理可在 doFilter 捕获所有异常afterCompletion 可捕获(但 pre/post 抛异常需全局处理)
典型场景编码转换、CORS、安全过滤(Spring Security 就是 Filter 链)日志、权限校验(Controller 级)、性能监控
Spring Boot 配置@WebFilter + @ServletComponentScan 或 FilterRegistrationBeanWebMvcConfigurer.addInterceptors()

结论

  • Filter 先执行(外层),适合全局/低级处理(如编码、CORS)。
  • Interceptor 后执行(内层),适合 Spring 生态特定逻辑(如访问 ModelAndView)。
  • 顺序:Filter → DispatcherServlet → Interceptor pre → Controller → Interceptor post → View → Interceptor after → Filter。

二、执行流程图(一次请求的顺序)

客户端请求
    ↓
Filter1 doFilter (pre)
    ↓
Filter2 doFilter (pre)
    ↓
DispatcherServlet
    ↓
Interceptor1 preHandle
    ↓
Interceptor2 preHandle (若返回 false,则中断)
    ↓
Controller 方法执行
    ↓
Interceptor2 postHandle
    ↓
Interceptor1 postHandle
    ↓
ViewResolver + 视图渲染
    ↓
Interceptor1 afterCompletion (不管异常)
    ↓
Interceptor2 afterCompletion
    ↓
Filter2 doFilter (post)
    ↓
Filter1 doFilter (post)
    ↓
响应返回客户端

三、Interceptor 配置 & 使用(Spring Boot 3 推荐)

实现 HandlerInterceptor 接口,重写 3 方法。

// 自定义拦截器(日志 + 权限示例)
@Slf4j
@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // pre: 请求前(可拒绝请求)
        log.info("preHandle: URL={}", request.getRequestURI());
        String token = request.getHeader("Authorization");
        if (token == null || !token.startsWith("Bearer ")) {
            response.setStatus(401);  // 未授权
            response.getWriter().write("Unauthorized");
            return false;  // 中断链
        }
        // 可注入 Service 校验 token
        return true;  // 放行
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // post: Controller 后,视图渲染前(可改 ModelAndView)
        log.info("postHandle: 添加额外模型");
        if (modelAndView != null) {
            modelAndView.addObject("extra", "intercepted");
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // after: 完成(清理资源,常用于日志/监控)
        log.info("afterCompletion: 执行耗时计算或异常处理");
        if (ex != null) {
            log.error("异常: {}", ex.getMessage());
        }
    }
}

注册(实现 WebMvcConfigurer):

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private AuthInterceptor authInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor)
                .addPathPatterns("/api/**")       // 拦截路径(Ant 风格)
                .excludePathPatterns("/api/public/**", "/login");  // 排除
                // .order(1);  // 指定顺序(可选)
    }
}

四、Filter 配置 & 使用(Spring Boot 3)

实现 Filter 接口。

// 自定义过滤器(编码 + CORS 示例)
@Slf4j
@WebFilter(urlPatterns = "/*", filterName = "encodingFilter")
@Order(1)  // 执行顺序(值越小越先)
public class EncodingFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        // pre: 请求前
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        log.info("Filter pre: {}", request.getRequestURI());

        // 放行
        chain.doFilter(request, response);

        // post: 响应后
        log.info("Filter post");
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化
    }

    @Override
    public void destroy() {
        // 销毁
    }
}

启用扫描(启动类):

@SpringBootApplication
@ServletComponentScan  // 扫描 @WebFilter
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

或用 FilterRegistrationBean(更灵活,可注入 Bean):

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<EncodingFilter> encodingFilter() {
        FilterRegistrationBean<EncodingFilter> reg = new FilterRegistrationBean<>();
        reg.setFilter(new EncodingFilter());
        reg.addUrlPatterns("/*");
        reg.setOrder(1);
        return reg;
    }
}

五、生产级最佳实践(2025 年)

  1. 登录/权限:Interceptor(可访问 Spring Bean 校验 JWT)。
  2. 全局编码/CORS/日志:Filter(最外层,覆盖所有)。
  3. Spring Security:内置 Filter 链,优先用它做认证。
  4. 多个链:Filter 用 @Order,Interceptor 用注册顺序。
  5. 异步支持:Filter 加 DispatcherType.ASYNC/ERROR。
  6. 坑点避坑
  • Interceptor 不能拦截静态资源(用 Filter 或 ResourceHandler)。
  • Filter 不能注入 Bean(用 RegistrationBean 包装)。
  • 异常:用 @ControllerAdvice 全局捕获。

六、总结推荐

场景优先选择
全局请求修改/安全Filter
Controller 级逻辑Interceptor
混合使用Filter 先 + Interceptor 后

一句话:Filter 是 Servlet 的门卫,Interceptor 是 Spring MVC 的管家。

现在你能轻松配置了!想看完整登录拦截示例代码?或 AOP @Aspect 替代方案?继续问我,超详细教程等着你!

文章已创建 3070

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部