news 2026/5/4 16:28:11

过滤器和拦截器谁先执行?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
过滤器和拦截器谁先执行?

面试必问:过滤器和拦截器谁先执行?一图看懂执行顺序与核心区别

这是一道面试频率高达 80% 的 Java Web 题目。很多开发者能随口答出“Filter 先执行”,但当被问到“为什么”以及“如何配置执行顺序”时,就开始含糊了。本文将从调用链、源码层面、配置方式等多个维度彻底讲透 Filter 与 Interceptor 的执行顺序,并辅以流程图和对比表格,让你一次掌握。


一、直接结论

过滤器(Filter)先执行,拦截器(Interceptor)后执行。

更精确地说,在一个 Spring MVC 应用中,一个请求的完整执行顺序为:

客户端 → 过滤器(Filter) → 拦截器(Interceptor) → Controller → 拦截器(后置) → 过滤器(后置) → 客户端

如果项目中同时使用了 Filter 和 Interceptor,那么Filter 总是先于 Interceptor 执行,也晚于 Interceptor 结束(后置处理顺序相反)。


二、为什么 Filter 先于 Interceptor?—— 原理层面

要理解顺序,首先必须搞清楚 Filter 和 Interceptor 分别位于 Web 容器的哪一层。

客户端

Servlet容器
如Tomcat

FilterChain
过滤器链

Servlet

Spring MVC
DispatcherServlet

Interceptor
拦截器

Controller

2.1 Filter(过滤器) —— Servlet 容器级别

  • Filter 是Java Servlet 规范中定义的组件,位于Servlet 容器(如 Tomcat、Jetty)内部。
  • Filter 可以拦截所有进入 Servlet 容器的请求(包括静态资源、JSP、Servlet)。
  • 一个或多个 Filter 形成FilterChain,请求在进入Servlet之前会依次经过所有匹配的 Filter。

2.2 Interceptor(拦截器) —— Spring MVC 级别

  • Interceptor 是Spring MVC 框架提供的组件,位于DispatcherServlet调用Controller的过程当中。
  • Interceptor 只能拦截由DispatcherServlet处理的请求(通常是对应@Controller的请求路径),无法拦截静态资源(除非配置)。
  • Interceptor 依赖于 Spring 容器,可以利用 Spring 的依赖注入、AOP 等特性。

结论:由于 Filter 工作在 Servlet 容器层面,而 Interceptor 工作在更上层的 Spring MVC 内部,因此请求势必先经过 Filter 才会到达 Interceptor


三、完整调用时序图(附代码级顺序)

下面通过一个详细的时序图,展示从请求进入容器到响应返回的全流程,包含多个 Filter 和多个 Interceptor 的执行顺序。

InterceptorA (afterCompletion)InterceptorB (afterCompletion)InterceptorA (postHandle)InterceptorB (postHandle)ControllerInterceptorB (preHandle)InterceptorA (preHandle)DispatcherServletFilterBFilterAClientInterceptorA (afterCompletion)InterceptorB (afterCompletion)InterceptorA (postHandle)InterceptorB (postHandle)ControllerInterceptorB (preHandle)InterceptorA (preHandle)DispatcherServletFilterBFilterAClient视图渲染完成后请求doFilter() before chainchain.doFilter()doFilter() before chainchain.doFilter()preHandlepreHandle调用目标方法返回 ModelAndViewpostHandle继续响应返回doFilter() after chain继续链doFilter() after chain最终响应afterCompletionafterCompletion完成

执行顺序总结

  1. Filter 的doFilter()前置代码(按配置顺序)
  2. Interceptor 的preHandle()(按配置顺序)
  3. Controller 方法
  4. Interceptor 的postHandle()(按配置逆序
  5. 视图渲染(若适用)
  6. Interceptor 的afterCompletion()(按配置逆序
  7. Filter 的doFilter()后置代码(按配置逆序

四、代码验证(Spring Boot 示例)

4.1 定义一个简单的 Filter

@ComponentpublicclassMyFilterimplementsFilter{@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{System.out.println("Filter.doFilter() 前置");chain.doFilter(request,response);System.out.println("Filter.doFilter() 后置");}}

4.2 定义一个拦截器

@ComponentpublicclassMyInterceptorimplementsHandlerInterceptor{@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler){System.out.println("Interceptor.preHandle()");returntrue;}@OverridepublicvoidpostHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,ModelAndViewmv){System.out.println("Interceptor.postHandle()");}@OverridepublicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,Exceptionex){System.out.println("Interceptor.afterCompletion()");}}

4.3 配置拦截器(Spring Boot)

@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{@AutowiredprivateMyInterceptormyInterceptor;@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){registry.addInterceptor(myInterceptor).addPathPatterns("/**");}}

4.4 请求一个 Controller 接口,控制台输出结果:

Filter.doFilter() 前置 Interceptor.preHandle() --- 执行 Controller 方法 --- Interceptor.postHandle() Interceptor.afterCompletion() Filter.doFilter() 后置

结论:Filter 的前置逻辑确实在 Interceptor 的preHandle之前执行;而 Filter 的后置逻辑在 Interceptor 的所有后置方法完成之后才执行。


五、多 Filter / 多 Interceptor 的配置顺序如何影响执行顺序?

5.1 Filter 顺序控制

Spring Boot 中,Filter 的执行顺序由以下方式决定:

  • 使用@Order(1)注解(数字越小越先执行)。
  • 实现Ordered接口。
  • 通过FilterRegistrationBean设置setOrder()

示例:

@Bean@Order(1)publicFilterfilterA(){returnnewMyFilterA();}@Bean@Order(2)publicFilterfilterB(){returnnewMyFilterB();}

执行顺序:FilterA 前置 → FilterB 前置 → … → FilterB 后置 → FilterA 后置。

5.2 Interceptor 顺序控制

使用addInterceptor的顺序决定:

registry.addInterceptor(interceptorA).addPathPatterns("/**");registry.addInterceptor(interceptorB).addPathPatterns("/**");
  • preHandle执行顺序:A 先,B 后。
  • postHandleafterCompletion执行顺序:B 先,A 后(逆序)。

5.3 混合顺序示意图

Interceptor顺序

Filter顺序

Filter1前置

Filter2前置

Filter3前置

I1 preHandle

I2 preHandle

Controller

I2 postHandle

I1 postHandle

Filter3后置

Filter2后置

Filter1后置


六、Filter 和 Interceptor 的核心区别对比表

维度FilterInterceptor
规范层级Java Servlet 规范Spring MVC / 框架级
容器依赖Servlet 容器(Tomcat/Jetty)Spring 容器(IoC)
拦截范围可以拦截所有请求(包括静态资源、JSP)只能拦截由 DispatcherServlet 处理的请求
方法数量1 个核心方法:doFilter3 个核心方法:preHandlepostHandleafterCompletion
资源访问无法直接使用 Spring 的 Bean(需特殊处理)可直接注入任何 Spring 组件
适用场景编码/字符集过滤、鉴权、日志、跨域处理权限校验、日志、参数注入、性能监控
执行时机请求进入 Servlet 容器后最早执行在 DispatcherServlet 调用 Controller 前后
是否支持 AOP不支持(但可通过包装 Request/Response 变相实现)配合 Spring AOP 更灵活

七、常见面试追问与解答

Q1:能否让 Interceptor 比 Filter 先执行?

不能,因为 Filter 位于 Servlet 容器层面,Interceptor 位于 Spring MVC 层面。请求必须先经过 Servlet 容器才能到达 DispatcherServlet,这是物理上的层级限制。除非你把自己的逻辑写在 Filter 之前(如 Servlet 容器的 Valve),但那不属于 Filter/Interceptor 范畴。

Q2:Filter 和 Interceptor 都做权限校验,应该用哪个?

推荐使用 Filter。因为:

  • Filter 更早执行,可以提前拒绝非法请求,减少不必要的 Spring MVC 处理。
  • Filter 不依赖 Spring,可以用于非 Spring 环境(但现代项目这点不是主要因素)。
  • 但 Interceptor 可以更精细地获取 HandlerMethod 信息(如方法上的注解),如果用 Spring Security,它默认基于 Filter。

实际项目常见做法:全局 Token 校验用 Filter,方法级权限用 Spring Security 或 Interceptor + 注解。

Q3:如果在 Filter 中直接返回响应(不调用 chain.doFilter),Interceptor 还会执行吗?

不会chain.doFilter()负责将请求传递给下一个 Filter 或 Servlet。如果 Filter 直接response.getWriter().write(...)并返回,整个调用链中断,DispatcherServlet 不会被调用,因此 Interceptor 也不会执行。

Q4:如何控制多个 Filter 和 Interceptor 的终止?

  • Filter 中不调用chain.doFilter()即可终止。
  • Interceptor 中preHandle返回false即可终止后续 Interceptor 和 Controller 的执行,但已经执行过的 Filter 后置逻辑仍会执行(因为 Filter 的doFilter方法已经过了chain.doFilter调用点)。

八、总结

关键点结论
执行顺序Filter 先,Interceptor 后
原因Filter 工作在 Servlet 容器层,Interceptor 工作在 Spring MVC 层
Filter 多实例顺序@OrderFilterRegistrationBean决定(数字小优先)
Interceptor 多实例顺序addInterceptor的添加顺序决定 preHandle 顺序,逆序决定 postHandle/afterCompletion
Filter 终止不调用chain.doFilter()
Interceptor 终止preHandle返回false

一句话总结面试回答:Filter 先执行,因为它是 Servlet 容器的组件,位于 Spring MVC 的拦截器之前。如果需要详细展开,可以补充说明 Filter 和 Interceptor 各自所处的层级和调用链。


九、拓展思考

  • 如果项目同时使用了 Filter、Interceptor 和 AOP(如@Around),三者的执行顺序如何?欢迎动手实验。
  • 如何在 Filter 中获取 Spring 管理的 Bean?可以使用WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext).getBean(...)

📚参考阅读:Spring 官方文档——Interceptors

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/4 16:28:09

HT1621驱动段码LCD屏避坑指南:从引脚映射到地址调试的全流程解析

HT1621驱动段码LCD屏避坑指南:从引脚映射到地址调试的全流程解析 第一次拿到定制段码屏时,看着厂商提供的引脚定义表与HT1621标准文档不匹配的混乱对应关系,我盯着闪烁的屏幕整整两天没合眼。这种经历想必每个嵌入式工程师都深有体会——明明…

作者头像 李华
网站建设 2026/5/4 16:28:05

长期使用 Taotoken 聚合服务对开发流程效率的实际提升感受

长期使用 Taotoken 聚合服务对开发流程效率的实际提升感受 1. 统一接入带来的配置简化 在引入 Taotoken 之前,我们的开发团队需要为每个大模型服务单独管理 API Key 和配置参数。以 Claude 和 OpenAI 兼容模型为例,原先需要在代码库中维护多个环境变量…

作者头像 李华
网站建设 2026/5/4 16:27:00

PARROT基准:跨数据库SQL翻译的质量评估与实践

1. 项目背景与核心价值在数据驱动的时代,企业往往需要同时操作多种数据库系统。Oracle、MySQL、PostgreSQL等不同数据库方言间的SQL语法差异,就像不同国家间的语言障碍。PARROT基准的诞生,正是为了解决这个长期困扰开发者的痛点问题。过去三年…

作者头像 李华
网站建设 2026/5/4 16:25:45

Hunyuan-HY-MT1.5-1.8B对比评测:轻量架构翻译质量优势

Hunyuan-HY-MT1.5-1.8B对比评测:轻量架构翻译质量优势 1. 这不是“小模型”,而是更聪明的翻译选择 你有没有遇到过这样的情况:用大模型做翻译,结果等了半分钟,生成的句子却带着一股“AI腔”——生硬、绕口、漏译关键…

作者头像 李华
网站建设 2026/5/4 16:23:26

MNIST数字手写体识别

目录 1.图像数据的处理 2.多分类问题的输出层 3.基于MLP进行数字手写体识别 4.TensorBoard可视化工具 1.图像数据的处理 图像数据可以通过图像处理库Pillow读取,首先安装: pip install pillow pip install torchvision pip install tensorboard from PIL i…

作者头像 李华