过滤器和拦截器的区别是什么?
面试考察点
-
架构理解:面试官不仅仅是想知道两者的定义,更是想看你能否说清楚它们在请求处理链中的位置关系,以及为什么 Spring 要在 Filter 之外再设计一套 Interceptor。
-
实战经验:是否在项目中真正用过,能否举出合适的场景说明什么时候该用 Filter、什么时候该用 Interceptor,而不是笼统地说 "都能做"。
-
原理深度:能否从 Servlet 容器、Spring IoC、Spring MVC 的 DispatcherServlet 等层面解释两者的本质差异。
核心答案
一句话先给结论:过滤器(Filter)是 Servlet 规范的一部分,由 Servlet 容器管理;拦截器(Interceptor)是 Spring MVC 框架的一部分,由 Spring 容器管理。 两者都能在请求到达 Controller 前后做处理,但作用范围、生命周期、能获取的信息量完全不同。
核心区别一览表:
| 对比维度 | Filter(过滤器) | Interceptor(拦截器) |
|---|---|---|
| 规范归属 | Servlet 规范 | Spring MVC 框架 |
| 管理容器 | Servlet 容器(Tomcat) | Spring IoC 容器 |
| 作用范围 | 所有请求(包括静态资源) | 仅 DispatcherServlet 处理的请求 |
| 触发时机 | 在 DispatcherServlet 之前 | 在 DispatcherServlet 之内,Handler 执行前后 |
| 能否获取 Handler 信息 | 不能 | 能(方法名、参数、注解等) |
| 能否注入 Spring Bean | 默认不能(需额外配置) | 天然支持 |
| 典型场景 | 编码转换、跨域、压缩、全局通用 | 权限校验、日志、事务、业务相关 |
深度解析
一、请求处理链路
光看表格还不够直观,咱们来画一下一次 HTTP 请求的完整链路:
上图展示了一次完整请求的链路。整体可以分为三个层次来理解:
-
Filter 层(Servlet 容器层面):所有请求先进 Filter 链,Filter 不知道后面是 Spring 还是其他框架,它只认 Servlet。Filter 的执行顺序由注册顺序或
@Order决定。 -
DispatcherServlet 层(Spring MVC 入口):请求穿过 Filter 链后到达
DispatcherServlet,从这里开始进入 Spring 的地盘。DispatcherServlet负责根据 URL 找到对应的 Handler(即 Controller 方法)。 -
Interceptor 层(Spring MVC 框架层面):找到 Handler 之后、真正执行之前,先依次执行所有 Interceptor 的
preHandle()方法;Controller 执行完毕后,逆序执行postHandle();视图渲染完成后,再逆序执行afterCompletion()。
关键点在于:Filter 在 DispatcherServlet 外面,Interceptor 在里面。 这决定了它们能看到的、能做的事情完全不同。
二、代码实现对比
光说不练假把式,来两段代码感受下差异。
Filter 的实现:
@Component
public class AuthFilter implements Filter {
// 注意:Filter 接口来自 javax.servlet 包
// 不是 Spring 的接口,是 Servlet 规范定义的
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
// 前置处理
String token = req.getHeader("Authorization");
if (token == null) {
// 这里拿不到 Handler 信息,不知道要调用哪个 Controller 方法
((HttpServletResponse) response).sendError(401, "未登录");
return;
}
// 放行,交给下一个 Filter 或 Servlet
chain.doFilter(request, response);
// 后置处理(响应返回后)
System.out.println("请求处理完毕");
}
}
Interceptor 的实现:
@Component
public class AuthInterceptor implements HandlerInterceptor {
// 注意:这个接口来自 org.springframework.web.servlet 包
// 是 Spring MVC 专属的
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
// handler 就是目标 Controller 方法
// 可以拿到方法名、参数、注解等所有信息!
if (handler instanceof HandlerMethod) {
HandlerMethod method = (HandlerMethod) handler;
// 比如:检查方法上有没有某个自定义注解
RequireLogin annotation = method.getMethodAnnotation(RequireLogin.class);
if (annotation != null) {
String token = request.getHeader("Authorization");
if (token == null) {
response.sendError(401, "未登录");
return false; // 返回 false 就不继续往下走了
}
}
}
return true; // 放行
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) {
// Controller 执行后、视图渲染前
// 可以修改 ModelAndView
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
// 视图渲染后、响应返回前
// 适合做资源清理、异常日志记录
}
}
看出区别了吧?Interceptor 能拿到 handler 对象,这意味着它知道你要调用哪个 Controller 的哪个方法,方法上有哪些注解,参数是什么。Filter 就没那么幸运了,它只知道有个请求来了,至于后面交给谁处理,它一无所知。
三、Spring Bean 注入的差异
这块很多人踩坑。Filter 默认是由 Servlet 容器管理的,不是 Spring Bean,所以直接用 @Autowired 注入是拿不到的(Spring Boot 注册的 Filter 除外)。
// ❌ 这样注入的 userService 可能为 null
public class MyFilter implements Filter {
@Autowired
private UserService userService; // null!
}
解决方案有几种:
- Spring Boot 环境下用
FilterRegistrationBean注册,或者直接加@Component,Spring Boot 会自动处理 - 传统 Spring MVC 环境下用
DelegatingFilterProxy做桥接
而 Interceptor 就没这个问题,它本身就是 Spring 管理的 Bean,@Autowired 直接用,丝滑得很。
四、使用场景怎么选?
说个简单的判断标准:
用 Filter 的场景——和业务无关的通用处理:
- 字符编码转换(
CharacterEncodingFilter) - CORS 跨域处理
- GZIP 压缩
- XSS 防护(全局的)
- 请求日志记录(需要记录所有请求,包括静态资源的)
用 Interceptor 的场景——和业务相关的处理:
- 登录状态校验(需要知道哪个接口需要登录)
- 权限校验(需要知道方法上的权限注解)
- 操作日志(需要知道调的是哪个方法、谁调的)
- 事务管理
- 接口限流(针对特定接口)
一句话总结就是:通用选 Filter,业务选 Interceptor。
面试高频追问
-
追问一:一个请求可以同时被 Filter 和 Interceptor 拦截吗?执行顺序是什么?
当然可以。执行顺序是:Filter → DispatcherServlet → Interceptor.preHandle → Controller → Interceptor.postHandle → Interceptor.afterCompletion → Filter。Filter 永远在最外层。
-
追问二:Filter 链和 Interceptor 链的执行顺序怎么控制?
Filter 通过
@Order注解或FilterRegistrationBean的setOrder()控制顺序,值越小越先执行。Interceptor 通过WebMvcConfigurer的addInterceptors()方法注册顺序决定,先注册的先执行preHandle,后执行postHandle和afterCompletion(和 Filter 一样,是洋葱模型)。 -
追问三:Spring Boot 中 Filter 用
@Component注册和用FilterRegistrationBean注册有什么区别?@Component注册的 Filter 会拦截所有请求(/*),且无法精确控制顺序(虽然可以用@Order但语义不够明确)。FilterRegistrationBean可以精确配置 URL 匹配模式、执行顺序,还能控制是否启用,生产环境更推荐后者。
常见面试变体
- "Spring 中 Filter 和 Interceptor 有什么区别?各自适用什么场景?"
- "Spring Boot 请求处理链路是怎样的?Filter、Interceptor、Controller 的执行顺序?"
- "做一个登录校验,用 Filter 还是 Interceptor?为什么?"
记忆口诀
Filter 在外 Interceptor 在内,Filter 管 Servlet Interceptor 管 Handler,通用用 Filter 业务用 Interceptor。
记住三个关键差异:规范不同(Servlet vs Spring)、管理容器不同(Tomcat vs IoC)、能获取的信息不同(只知道有请求 vs 知道调哪个方法)。
总结
过滤器是 Servlet 规范的组件,由容器管理,适合做通用的、和框架无关的预处理;拦截器是 Spring MVC 的组件,由 Spring 管理,能获取 Handler 信息,适合做业务相关的处理。记住 "Filter 在 DispatcherServlet 外面,Interceptor 在里面" 这个核心位置关系,执行顺序和作用范围的差异就全通了。
