
这是一个超级经典的问题,能很好地考察候选人对SpringBoot(以及底层Servlet和Spring MVC)请求处理流程的理解。
过滤器和拦截器功能上类似,都是用于在请求处理过程中进行横切关注点的处理,列如日志记录、权限校验、性能监控等。但它们在本质、作用范围、实现方式和能力上有根本的区别。
我将从以下几个方面来阐述它们的区别:
1. 本质和归属不同 (Fundamental Difference)
- 过滤器 (Filter): 是 Servlet 规范 规定的,属于 Web 服务器 层面的组件。它的存在不依赖于任何框架(如Spring),只要是基于Servlet的Web应用(如Tomcat、Jetty)都能使用。它的核心接口是 javax.servlet.Filter。
- 拦截器 (Interceptor): 是 Spring MVC 框架 自身的组件,由 Spring 容器 管理。它依赖于Spring框架,深度集成在Spring的应用程序上下文(ApplicationContext)中。它的核心接口是 org.springframework.web.servlet.HandlerInterceptor。
简单比喻:过滤器是机场的出入境安检(属于国家层面,所有旅客都必须经过),而拦截器是航空公司自己VIP休憩室的接待员(属于公司层面,只服务自己的乘客)。
2. 拦截范围和作用域不同 (Scope of Interception)
这是最核心的区别,决定了它们的使用场景。
- 过滤器: 拦截的是所有进入Web容器的请求。它可以对几乎所有的请求进行过滤,包括:
- 静态资源(如 /static/**.css, /public/**.js)
- 非Spring管理的请求(列如直接访问一个Servlet)
- 当然也包括所有进入Spring MVC的请求。
- 作用范围更广。
- 拦截器: 拦截的是进入Spring MVC DispatcherServlet 之后的请求。它只能拦截Controller的请求。
- 它不会拦截静态资源。
- 它不会拦截已经绕过DispatcherServlet的请求。
- 作用范围更窄,但更专注。
3. 实现方式和注入能力不同 (Implementation and Injection)
- 过滤器: 通过实现 javax.servlet.Filter 接口,重写 doFilter() 方法。它是一个标准的Servlet组件,由Web容器(如Tomcat)实例化和调用。
- 一般无法直接使用Spring的依赖注入。由于Filter由Servlet容器管理,而Bean由Spring容器管理。如果要注入,需要通过一些特殊方式,例如:
- 使用 DelegatingFilterProxy(Spring Boot自动配置的默认方式)。
- 在Filter类上使用 @Component 并重写 GenericFilterBean。
- 处理的是原始的 ServletRequest 和 ServletResponse。
- 拦截器: 通过实现 HandlerInterceptor 接口或继承 HandlerInterceptorAdapter,重写 preHandle, postHandle, afterCompletion 方法。
- 可以直接使用Spring的依赖注入,由于它本身就是一个Spring Bean(需要在配置中通过 @Autowired 注入并注册到拦截器 registry 中)。
- 处理的是Spring包装后的 HttpServletRequest、HttpServletResponse 和 HandlerMethod 对象,能获取到更多的控制器和方法信息。
4. 控制粒度不同 (Control Granularity)
- 拦截器 提供了更精细的三个生命周期控制点,这是过滤器所不具备的:
- preHandle(…): Controller方法执行前调用。常用于权限校验、日志记录。返回 true 则继续,返回 false 则中断流程。
- postHandle(…): Controller方法执行后,视图渲染前调用。可以对ModelAndView进行操作。
- afterCompletion(…): 整个请求完成后调用(视图已渲染完毕)。常用于资源清理、性能监控(计算整个请求耗时)。
- 过滤器 主要通过一个 doFilter() 方法进行处理,虽然也能通过 FilterChain 控制流程,但无法准确地在“Controller方法执行前/后”这样的时间点进行干预。
5. 执行顺序 (Execution Order)
在一个典型的SpringBoot请求处理流程中,它们的执行顺序超级清晰:
请求进入 -> 过滤器1 -> 过滤器2 -> … -> DispatcherServlet -> 拦截器.preHandle -> Controller -> 拦截器.postHandle -> 视图渲染 -> 拦截器.afterCompletion -> 响应返回 -> 过滤器2 -> 过滤器1
注意:过滤器的执行顺序与 Filter 注册的顺序有关,可以通过 @Order 注解或调整Filter类名的字母顺序来控制。拦截器的执行顺序取决于在配置类中 addInterceptor 的顺序。
总结与使用场景提议
为了更直观,我用一个表格来总结:
|
特性 |
过滤器 (Filter) |
拦截器 (Interceptor) |
|
归属 |
Servlet 规范 |
Spring MVC 框架 |
|
作用范围 |
所有Web请求(静态资源、Servlet等) |
仅Spring MVC管理的Controller请求 |
|
依赖注入 |
不支持(需特殊处理) |
原生支持 |
|
控制粒度 |
粗粒度,基于请求-响应 |
细粒度,可挂钩MVC生命周期 |
|
获取信息 |
原始的Servlet对象 |
Spring包装的Handler、ModelAndView等 |
|
使用场景 |
内容过滤(如敏感词过滤)、跨域处理(CORS)、全局日志、字符编码转换 |
权限检查、业务日志、参数预处理、Controller增强 |
如何选择?
- 如果需要过滤所有请求,包括静态资源,或者处理与Servlet API强相关的底层操作(如乱码解决),使用过滤器。
- 如果只需要处理Controller的请求,并且需要用到Spring的特性(如依赖注入)、或者需要精细地控制MVC流程(如在方法执行前后做特定操作),使用拦截器。
在实际项目中,它们常常是协同工作的。例如,先用过滤器解决全局字符编码和跨域问题,再用拦截器做登录状态和权限的校验。
以上就是我对SpringBoot2中过滤器与拦截器区别的理解。



收藏了,感谢分享