Spring Web MVC 中,过滤器(Filter) 和 拦截器(Interceptor)

在 Spring Web MVC 中,过滤器(Filter) 和 拦截器(Interceptor) 都是用来对请求进行预处理和后处理的组件,但它们属于不同的技术体系,作用范围和使用场景有明显区别。

一、核心区别对比

 
对比项Filter(过滤器)Interceptor(拦截器)
规范来源 Servlet 规范(J2EE) Spring MVC 框架
作用容器 Servlet 容器(Tomcat 等) Spring 容器
拦截范围 所有请求(包括静态资源、JSP、Servlet) 只拦截 Spring MVC 的 Handler(Controller 方法)
能否获取 Spring Bean 默认不能,需特殊配置 可以直接注入 Spring Bean
能否获取 Handler 信息 不能 可以(HandlerMethod)
执行顺序 在 DispatcherServlet 之前 在 DispatcherServlet 之后,Handler 之前/之后
典型接口 javax.servlet.Filter HandlerInterceptor

二、执行流程图

HTTP 请求
   │
   ▼
┌─────────────┐
│  Filter     │  ← 过滤器(可多个)
│  chain      │
└─────────────┘
   │
   ▼
DispatcherServlet
   │
   ▼
┌─────────────┐
│ Interceptor │  ← preHandle
│  preHandle  │
└─────────────┘
   │
   ▼
  Handler(Controller 方法)
   │
   ▼
┌─────────────┐
│ Interceptor │  ← postHandle
└─────────────┘
   │
   ▼
┌─────────────┐
│ Interceptor │  ← afterCompletion
└─────────────┘
   │
   ▼
  Filter 后置处理
   │
   ▼
HTTP 响应

三、过滤器(Filter)

1. 实现方式

@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {

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

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        System.out.println("Filter 前置处理");
        chain.doFilter(request, response); // 放行
        System.out.println("Filter 后置处理");
    }

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

2. 注册方式

方式一:@WebFilter 注解(需在启动类加 @ServletComponentScan

@SpringBootApplication
@ServletComponentScan
public class Application { }

方式二:FilterRegistrationBean 配置

@Configuration
public class FilterConfig {

@Bean
public FilterRegistrationBean<MyFilter> myFilter() {
FilterRegistrationBean<MyFilter> bean = new FilterRegistrationBean<>();
bean.setFilter(new MyFilter());
bean.addUrlPatterns("/*");
bean.setOrder(1);
return bean;
}
}

四、拦截器(Interceptor)

1. 实现方式

 
public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        System.out.println("preHandle:Controller 执行前");
        // 返回 false 则中断请求
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler,
                           ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle:Controller 执行后,视图渲染前");
    }

    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception ex) throws Exception {
        System.out.println("afterCompletion:视图渲染后");
    }
}
 

2. 注册方式

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/login", "/static/**")
                .order(1);
    }
}

3. 三个方法执行时机

 
方法执行时机常见用途
preHandle Controller 方法执行前 登录校验、权限校验、参数校验
postHandle Controller 执行后,视图渲染前 修改 ModelAndView、日志
afterCompletion 视图渲染后(请求完成) 资源清理、耗时统计

注意:若 preHandle 返回 false,后续的 postHandle 和 afterCompletion 都不会执行(但已通过的前置拦截器的 afterCompletion 会执行)。

五、执行顺序
多个 Filter:按 @Order 或注册顺序执行,chain.doFilter 之前正序,之后逆序。

多个 Filter 组成过滤器链时,代码的执行顺序。核心点在于:chain.doFilter() 是一个"分界线",它之前和之后的代码执行方向相反。


一、先理解单个 Filter 的结构

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
    // ① chain.doFilter 之前的代码
    System.out.println("前置");
    
    chain.doFilter(req, resp);  // ② 放行,进入下一个 Filter 或目标资源
    
    // ③ chain.doFilter 之后的代码
    System.out.println("后置");
}
  • ① 之前:请求进入时执行(前置处理)

  • ② 放行:把请求交给链中的下一个环节

  • ③ 之后:下一个环节处理完、返回响应时执行(后置处理)

所以同一个 Filter 内部就是"先进后出"的栈式结构。

二、两个 Filter 的实际执行顺序

假设注册顺序(或 @Order 值)为:

FilterA (order = 1)
FilterB (order = 2)

代码:

public class FilterA implements Filter {
    public void doFilter(...) {
        System.out.println("A - 前置");
        chain.doFilter(req, resp);
        System.out.println("A - 后置");
    }
}

public class FilterB implements Filter {
    public void doFilter(...) {
        System.out.println("B - 前置");
        chain.doFilter(req, resp);
        System.out.println("B - 后置");
    }
}

执行结果:

A - 前置
B - 前置
   ← 到达 Controller / 目标资源
B - 后置
A - 后置
 

为什么是"前置正序,后置逆序"?

可以把过滤器链想象成洋葱或递归调用:

A.doFilter 开始
  │
  ├─ 打印 "A-前置"
  │
  ├─ chain.doFilter()  →  进入 B
  │       │
  │       ├─ 打印 "B-前置"
  │       │
  │       ├─ chain.doFilter()  →  进入 Controller
  │       │       │
  │       │       └─ 处理请求,返回
  │       │
  │       ├─ 打印 "B-后置"   ← 从 Controller 返回后
  │       │
  │       └─ B 结束
  │
  ├─ 打印 "A-后置"           ← 从 B 返回后
  │
  └─ A 结束

多个 Interceptor:

preHandle:按注册顺序正序执行

postHandle:按注册顺序逆序执行

afterCompletion:按注册顺序逆序执行

Filter 与 Interceptor 的顺序:

Filter.pre → Interceptor.preHandle → Controller
→ Interceptor.postHandle → Interceptor.afterCompletion → Filter.post

 
posted @ 2026-09-15 22:17  KLAPT  阅读(8)  评论(0)    收藏  举报