Spring 里的过滤器(Filter)和拦截器(Interceptor)到底啥区别?

Spring 里的 Filter 和 Interceptor 到底有什么区别?

这是 Spring 项目中非常高频的一个面试/实战问题。
Filter 和 Interceptor 都能实现“在请求到达 Controller 前/后做一些统一处理”,但它们底层机制、执行时机、能做的事情、控制粒度完全不同。

下面用表格 + 核心维度 + 代码示例,把两者的区别讲透。

一、核心对比表(面试最常用版本)

维度Filter (javax.servlet.Filter / jakarta.servlet.Filter)Interceptor (HandlerInterceptor)谁更常用?(2025-2026)
所属规范Servlet 规范(Web 容器层面)Spring MVC 框架层面
执行时机在 DispatcherServlet 之前(请求进入 Servlet 容器后最早)在 DispatcherServlet 之后,HandlerMapping 之后
作用范围所有到达 Servlet 的请求(包括 .jsp、静态资源、Servlet 等)只作用于 Spring MVC 管理的请求(Controller)Filter 范围更大
能否获取 Spring 容器中的 Bean不能(容器启动时初始化)可以(通过 Spring 管理)Interceptor 更强
能否修改 request/response可以(包装 Request/Response)只能在 pre/post 阶段有限修改(基本靠 HttpServletRequestWrapper)Filter 更灵活
能否阻止请求继续可以(不调用 chain.doFilter() 就阻断)可以(preHandle 返回 false 就阻断)差不多
异常处理能力无法处理 Controller 抛出的异常可以(afterCompletion 能捕获)Interceptor 更强
执行顺序先执行 Filter → 再执行 InterceptorFilter 先
典型使用场景编码转换、字符集处理、CORS、全局 XSS 过滤、请求日志、静态资源放行登录校验、权限校验、日志记录、性能监控、国际化参数注入看需求
是否能注入 Spring Bean传统 Filter 不行(需配合 DelegatingFilterProxy)天生可以(@Component 或配置类注册)Interceptor 更方便
配置方式web.xml 或 @WebFilter + @ServletComponentScan实现 HandlerInterceptor + 加入 WebMvcConfigurer

二、执行顺序图(非常重要,面试常画)

客户端请求
    ↓
Servlet Filter(多个,按配置顺序)
    ↓
DispatcherServlet(Spring MVC 前置控制器)
    ↓
HandlerMapping(找 Controller)
    ↓
**HandlerInterceptor.preHandle()**   ← 这里可以阻断
    ↓
Controller 方法执行
    ↓
**HandlerInterceptor.postHandle()**  ← 响应生成前
    ↓
视图渲染(ViewResolver)
    ↓
**HandlerInterceptor.afterCompletion()**  ← 整个请求结束(可捕获异常)
    ↓
Servlet Filter(响应回来的路,逆序)
    ↓
返回客户端

一句话总结执行顺序
Filter 先于 Interceptor 执行,Interceptor 后于 Filter 执行

三、代码对比(最直观)

1. Filter 示例(全局字符编码 + 日志)

@WebFilter(urlPatterns = "/*")
@Order(1)
public class EncodingFilter implements Filter {

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

        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");

        System.out.println("Filter before: " + request.getRequestURI());
        chain.doFilter(req, resp);
        System.out.println("Filter after");
    }
}

2. Interceptor 示例(登录校验)

@Component
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 可以直接 @Autowired UserService
        String token = request.getHeader("Authorization");
        if (StringUtils.isBlank(token)) {
            response.setStatus(401);
            return false;
        }
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) throws Exception {
        // 可以记录耗时、异常日志
        if (ex != null) {
            log.error("Controller 异常", ex);
        }
    }
}

注册方式:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;

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

四、实际项目中怎么选?

需求场景推荐使用原因简述
全局编码转换、CORS、请求/响应包装Filter范围最大、最早执行
静态资源放行、swagger、druid 监控页面放行Filter这些请求不进 Spring MVC
登录、权限、角色校验Interceptor能获取 Spring 容器资源,逻辑更丰富
记录 Controller 方法耗时、异常统一处理InterceptorafterCompletion 能捕获异常
需要同时做请求和响应处理的复杂逻辑Filter可以完整包装 request/response
微服务网关层统一鉴权、限流Filter / GatewayFilter更早拦截

五、面试一句话总结(背下来)

Filter 是 Servlet 层面的,范围更大、更早执行,适合做通用 Web 容器级处理;Interceptor 是 Spring MVC 层面的,粒度更细,能方便使用 Spring 容器资源,适合做业务相关的拦截和后置处理。

你项目里现在主要用哪个做登录/鉴权?遇到过什么坑吗?可以继续聊聊具体场景。

文章已创建 4542

发表回复

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

相关文章

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

返回顶部