过滤器和拦截器有什么区别?
在 Web 开发中,过滤器(Filter)和拦截器(Interceptor)是两个常用的组件,它们都能对请求进行预处理和后处理。但很多开发者对两者的区别存在疑惑,本文将从技术实现、应用场景、核心特性等多个维度深入解析二者的差异。
一、定义与核心作用对比
1. 过滤器(Filter)
-
技术定位:Servlet 规范的原生组件,基于 Java EE 标准,所有支持 Servlet 的容器(如 Tomcat、Jetty)都内置支持
-
核心接口:实现javax.servlet.Filter接口,包含三个核心方法:
init(FilterConfig config) // 初始化方法
doFilter(ServletRequest request, ServletResponse response, FilterChain chain) // 核心处理方法
destroy() // 销毁方法
-
核心作用:对请求 / 响应进行链式过滤处理,主要用于处理与 Servlet 生命周期相关的通用功能,如:
-
请求参数编码处理(CharacterEncodingFilter)
-
权限验证(登录状态检查)
-
响应数据压缩(GZipFilter)
-
敏感词过滤
-
跨域请求处理(CORSFilter)
2. 拦截器(Interceptor)
-
技术定位:Spring MVC 框架特有的组件,基于 Spring 生态的 AOP 思想实现
-
核心接口:实现org.springframework.web.servlet.HandlerInterceptor接口,包含三个核心方法:
preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) // 控制器方法执行前调用
postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) // 控制器方法执行后调用
afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) // 整个请求完成后调用(包括视图渲染完成)
-
核心作用:对控制器(Controller)的访问进行精细化拦截控制,主要用于处理与业务逻辑更相关的功能,如:
-
接口访问频率限制
-
方法级权限校验
-
性能监控(计算接口响应时间)
-
请求参数预处理(如数据格式转换)
-
响应结果后处理(如添加统一响应头)
二、应用场景与触发时机差异
1. 执行流程对比
| 阶段 | 过滤器(Filter) | 拦截器(Interceptor) |
|---|---|---|
| 请求进入 | 最先触发,在 Servlet 容器接收请求后立即执行 | 在 DispatcherServlet 解析处理器映射之后触发 |
| 控制器调用前 | 属于 FilterChain 的一部分,按注册顺序执行 | preHandle () 方法在此阶段执行 |
| 控制器调用后 | - | postHandle () 方法在此阶段执行(视图渲染前) |
| 响应返回前 | 属于 FilterChain 的一部分,按逆序执行 | afterCompletion () 方法在此阶段执行(视图渲染后) |
| 请求结束 | 最后执行(FilterChain 执行完毕后) | 最后执行(整个请求处理流程结束后) |
2. 典型应用场景
-
过滤器更适合处理:
-
与 Servlet 规范强相关的底层处理(如请求体解析、响应流包装)
-
需要在整个 Web 应用范围生效的通用功能
-
对性能要求极高的场景(原生 Servlet 实现,轻量高效)
-
拦截器更适合处理:
-
Spring MVC 框架内的控制器级别的拦截(支持对 @Controller 和 @GetMapping 等注解的识别)
-
需要访问 Spring 上下文(如注入 Service 组件)的业务逻辑处理
-
支持细粒度的路径匹配(可配置只拦截特定的 URL 模式)
三、实现原理与技术架构对比
1. 底层实现机制
- 过滤器实现原理:
-
Servlet 容器启动时加载 Filter 配置,创建 Filter 实例并调用 init () 初始化
-
每个请求到达时,容器创建 FilterChain 对象,按注册顺序依次调用 doFilter () 方法
-
调用 chain.doFilter () 会传递到下一个 Filter 或目标 Servlet
-
响应返回时按相反顺序执行后续过滤逻辑
- 拦截器实现原理:
-
Spring MVC 启动时,通过 InterceptorRegistry 注册拦截器(可通过 WebMvcConfigurer 配置)
-
DispatcherServlet 在处理请求时,先获取 HandlerExecutionChain(包含处理器和拦截器列表)
-
按顺序调用拦截器的 preHandle (),全部返回 true 才会执行控制器方法
-
控制器执行完毕后,按逆序调用 postHandle ()
-
视图渲染完成后,调用 afterCompletion ()
2. 注册方式对比
-
过滤器注册(三种方式):
-
web.xml 配置:
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>com.example.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- @WebFilter 注解(Servlet 3.0+):
@WebFilter(urlPatterns = "/*", filterName = "encodingFilter")
public class EncodingFilter implements Filter { ... }
- Spring Boot 中通过 FilterRegistrationBean 注册:
@Bean
public FilterRegistrationBean<EncodingFilter> encodingFilterRegistration() {
FilterRegistrationBean<EncodingFilter> bean = new FilterRegistrationBean<>();
bean.setFilter(new EncodingFilter());
bean.addUrlPatterns("/*");
return bean;
}
- 拦截器注册(Spring MVC 方式):
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/api/**") // 拦截路径
.excludePathPatterns("/api/public/**"); // 排除路径
}
}
四、功能粒度与灵活性对比
1. 处理对象差异
-
过滤器:处理的是ServletRequest和ServletResponse的原始对象,只能在 Servlet 规范定义的接口范围内操作,无法直接访问 Spring Bean 或控制器方法细节
-
拦截器:可以访问HttpServletRequest和HttpServletResponse,还能获取:
-
处理器对象(handler,可能是 Controller 方法、静态资源等)
-
ModelAndView 对象(在 postHandle 阶段)
-
异常信息(在 afterCompletion 阶段)
-
支持直接注入 Spring Bean(通过 @Autowired)
2. 控制能力对比
| 特性 | 过滤器 | 拦截器 |
|---|---|---|
| 路径匹配粒度 | 基于 URL 模式(如 /、/api/) | 支持 Ant 风格路径(如 /user/**)和正则表达式 |
| 条件判断支持 | 有限(主要依赖 URL 匹配) | 强大(可在 preHandle 中编写复杂逻辑) |
| 对异步请求的支持 | 部分支持(需特殊处理异步流程) | 完全支持(Spring MVC 原生支持异步处理) |
| 访问响应结果 | 只能通过 ServletResponse 操作 | 可通过 ModelAndView 修改视图数据 |
| 终止请求能力 | 通过不调用 chain.doFilter () 终止 | 通过 preHandle 返回 false 终止 |
3. 典型功能实现对比
-
实现请求日志记录:
-
过滤器实现:在 doFilter 中记录请求 URL、时间戳,无法获取控制器方法名
-
拦截器实现:在 preHandle 中通过 handler 获取具体的 Controller 方法(需转换为 HandlerMethod),可记录方法名、参数等详细信息
五、使用范围与框架相关性
1. 技术栈依赖性
-
过滤器:
-
属于 Java EE 标准,不依赖任何框架,可在纯 Servlet 环境中使用
-
支持所有符合 Servlet 规范的容器(从 Servlet 2.3 到最新的 5.0 版本)
-
可与任何 Web 框架(Struts2、Spring MVC、Jakarta EE 等)配合使用
-
拦截器:
-
是 Spring MVC 特有的组件,必须运行在 Spring 生态环境中
-
依赖 Spring 框架的上下文环境,无法在纯 Servlet 或其他框架(如 Jakarta EE 原生 API)中使用
-
深度集成 Spring MVC 的处理器映射(HandlerMapping)和视图解析流程
2. 执行顺序规则
-
过滤器顺序:
-
由注册顺序决定(web.xml 中的顺序或 @WebFilter 的 order 属性)
-
多个过滤器形成严格的链式结构,执行顺序不可逆
-
拦截器顺序:
-
由 addInterceptors 方法中的注册顺序决定(先注册的先执行 preHandle,后注册的先执行 postHandle)
-
支持多个拦截器的组合使用,形成责任链模式
六、如何选择使用过滤器还是拦截器?
1. 功能层级决策
-
选择过滤器的场景:
-
需要处理最底层的请求 / 响应数据(如修改请求头、响应体)
-
功能需要在整个 Web 应用范围生效(包括静态资源、错误页面等)
-
希望兼容非 Spring 环境(如纯 Servlet 项目)
-
对性能有极高要求(原生实现通常比框架组件更快)
-
选择拦截器的场景:
-
需要针对控制器方法进行精细化拦截(如只拦截 @RestController 标注的接口)
-
业务逻辑需要访问 Spring Bean(如调用 Service 进行权限校验)
-
需要处理控制器方法的返回结果(修改 ModelAndView)
-
需要使用更灵活的路径匹配规则(支持排除路径、正则表达式)
2. 最佳实践
- 组合使用:在实际项目中,过滤器和拦截器通常配合使用,例如:
-
过滤器处理编码、跨域等底层通用功能
-
拦截器处理接口权限、性能监控等业务相关功能
-
性能优化:对于不需要访问 Spring 上下文的通用功能,优先使用过滤器以减少框架层开销
-
复杂逻辑处理:涉及业务逻辑或需要操作 ModelAndView 时,必须使用拦截器
总结
过滤器和拦截器虽然都是请求处理组件,但在技术定位、实现原理和应用场景上有明显区别:
| 对比维度 | 过滤器(Filter) | 拦截器(Interceptor) |
|---|---|---|
| 技术规范 | Servlet 规范(Java EE 标准) | Spring MVC 框架专属 |
| 核心接口 | javax.servlet.Filter | org.springframework.web.servlet.HandlerInterceptor |
| 作用范围 | 整个 Web 应用(包括静态资源) | Spring MVC 控制器级别 |
| 处理对象 | ServletRequest/Response 原始对象 | 包含处理器细节的 HttpServletRequest/Response |
| 框架依赖 | 无(纯 Java EE) | 依赖 Spring 框架 |
| 典型应用 | 编码处理、权限校验、日志记录 | 方法级拦截、性能监控、数据预处理 |
| 注册方式 | web.xml/@WebFilter/FilterRegistrationBean | WebMvcConfigurer.addInterceptors() |
理解两者的差异后,开发者可以根据具体需求选择合适的组件:过滤器适合处理底层通用功能,拦截器适合处理与 Spring MVC 深度整合的业务逻辑。在复杂项目中,二者通常协同工作,共同构建高效的请求处理流程。
2万+

被折叠的 条评论
为什么被折叠?



