面试官:谈谈SpringBoot2过滤器和拦截器的区别?

内容分享3周前发布
0 1 0

面试官:谈谈SpringBoot2过滤器和拦截器的区别?

这是一个超级经典的问题,能很好地考察候选人对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
    • 处理的是原始的 ServletRequestServletResponse
  • 拦截器: 通过实现 HandlerInterceptor 接口或继承 HandlerInterceptorAdapter,重写 preHandle, postHandle, afterCompletion 方法。
    • 可以直接使用Spring的依赖注入,由于它本身就是一个Spring Bean(需要在配置中通过 @Autowired 注入并注册到拦截器 registry 中)。
    • 处理的是Spring包装后的 HttpServletRequestHttpServletResponseHandlerMethod 对象,能获取到更多的控制器和方法信息。

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中过滤器与拦截器区别的理解。

© 版权声明

相关文章

1 条评论

您必须登录才能参与评论!
立即登录