文中代码基于 Java 17
Spring 拦截器与 Servlet Filter 的异同
Spring 的拦截器(Interceptor)与 Servlet 的 Filter 有相似之处,比如二者都是 AOP 编程思想的体现,都能实现权限检查、日志记录等。
不同的是:
- 使用范围不同:Filter 是 Servlet 规范规定的,只能用于 Web 程序中。而拦截器既可以用于 Web 程序,也可以用于 Application、Swing 等程序中。
- 规范不同:Filter 是 Servlet 规范中定义的,是 Servlet 容器支持的。而拦截器是在 Spring 容器内的,是 Spring 框架支持的。
- 使用资源不同:同其他代码块一样,Interceptor 也是一个 Spring 的组件,归 Spring 管理,配置在 Spring 文件中,因此能使用 Spring 里的任何资源、对象,例如 Service 对象、数据源、事务管理等,通过 IoC 注入拦截器即可。而 Filter 则不能。
- 深度不同:Filter 只在 Servlet 前后起作用。而拦截器能够深入到方法前后、异常抛出前后等。因此拦截器的使用具有更大的弹性。所以在 Spring 架构的程序中,要优先使用拦截器。
对于一个请求,拦截器、过滤器执行流程如下:
flowchart LR A((request)) B(Filter) C(Servlet) D(Interceptor) E(Controller) F((doService)) A --> B --> C --> D --> E --> F
何时使用 Filter、Interceptor?
- 如果是非 Spring 项目,那么拦截器不能用,只能使用过滤器。
- 如果是处理
Controller前后,既可以使用拦截器也可以使用过滤器。 - 如果是处理
DispatcherServlet前后,只能使用过滤器。
Spring Boot 使用 Filter
Spring Boot 使用 Filter 有两种方式:
- 使用 Spring Boot 提供的
FilterRegistrationBean注册 Filter - 使用原生 Servlet 注解
@WebFilter定义 Filter
使用 FilterRegistrationBean 注册 Filter
- 自定义 Filter 并实现
jakarta.servlet.Filter。(低版本 JDK 请使用javax.servlet.Filter)
| |
- 自定义配置类配置 Filter
| |
使用原生 Servlet 注解 @WebFilter 定义 Filter
- 自定义 Filter 并实现
jakarta.servlet.Filter(低版本 JDK 请使用javax.servlet.Filter),同时添加@WebFilter注解。
| |
- 在启动类上添加
@ServletComponentScan注解
| |
自定义过滤器执行顺序
使用自定义配置类配置过滤器时,可通过 setOrder() 方法设置过滤器执行顺序。如不设置,则按照 Spring Boot Bean 加载顺序。
使用 Servlet 原生注解 @WebFilter 时,只能通过限定 Filter 类型(按字母表 A - Z 的顺序)。注意:此方式使用 @Order 注解无效。
Spring Boot 使用 Interceptor
当请求来到
DispatcherServlet时,它会根据HandlerMapping的机制找到处理器,这样就会返回一个HandlerExecutionChain对象。这个对象包含处理器和拦截器。这里的拦截器会对处理器进行拦截,这样通过拦截器就可以增强处理器的功能。 ——《深入浅出 Spring Boot 2.X》- 杨开振
拦截器的设计(Interceptor 接口)
所有的拦截器都需要实现 HandlerInterceptor 接口。该接口主要定义如下:
| |
这些方法的执行流程如下:
- 执行
preHandler()方法。该方法会返回一个布尔值。如果为false,则结束所有流程;如果为true,则执行下一步 - 执行处理器逻辑。它包含控制器的功能。
- 执行
postHandle()方法。 - 执行视图解析和视图渲染。
- 执行
afterCompletion()方法。
开发拦截器
定义简单拦截器
实现 HandlerInterceptor 接口,并实现其方法:
| |
注册拦截器
新建配置类并实现 WebMvcConfigurer 接口,重写 addInterceptors(InterceptorRegistry registry) 方法:
| |
多个拦截器顺序
多个拦截器拦截同一路径时,采用责任链模式的规则,对于处理器前方法采用先注册先执行,而处理后方法和完成方法则是先注册后执行的规则。
当多个拦截器中某一个处理前(
preHandle())方法为false时,则后续拦截器、处理器和所有拦截器的处理器后(postHandle())方法都不会执行。完成方法(afterCompletion())则不一样,它只会执行返回true的拦截器的完成方法,而且顺序是先注册后执行。


感谢您的耐心阅读!来选个表情,或者留个评论吧!