在 Spring Boot 项目中,我们经常会遇到需要在请求处理前后执行一些通用逻辑的场景,比如记录日志、权限校验、全局异常处理等。此时,我们通常会面临两种选择:过滤器(Filter) 和 拦截器(Interceptor)。
虽然两者都能实现类似的功能,但它们在实现原理、使用场景、执行时机等方面有着本质的区别。本文将带你深入剖析这两者的差异,并通过实战案例,让你彻底搞懂何时该用过滤器,何时该用拦截器。

一、核心概念:从根上理解它们的区别
1.1 过滤器(Filter)
- 规范层级 :属于 Java Servlet 规范 的一部分,由 Servlet 容器(如 Tomcat)直接管理。
- 作用范围:对整个 Web 应用生效,包括静态资源(如 HTML、CSS、JS 等)。
- 触发时机 :在请求进入 DispatcherServlet 之前,以及响应返回客户端之后。
- 依赖关系:不依赖 Spring 容器,可以脱离 Spring 独立使用。
1.2 拦截器(Interceptor)
- 规范层级:Spring MVC 框架提供的机制,由 Spring 容器管理。
- 作用范围 :仅对 Spring MVC 控制器(Controller) 的请求生效,默认不拦截静态资源。
- 触发时机 :在请求进入 DispatcherServlet 之后,到达 Controller 之前,以及 Controller 处理完请求之后。
- 依赖关系:深度集成 Spring 容器,可以方便地使用 Spring 的依赖注入(DI)和 AOP 功能。
特性对比 | 过滤器(Filter) | 拦截器(Interceptor) |
---|---|---|
规范层级 | Java Servlet 规范 | Spring MVC 框架 |
作用范围 | 所有请求(包括静态资源) | 仅 Controller 请求 |
触发时机 | DispatcherServlet 前后 | Controller 前后 |
依赖容器 | Servlet 容器 | Spring 容器 |
能否修改请求/响应 | 可以直接修改 | 不能直接修改,但可操作 Model 和 View |
二、执行流程:一个图看懂它们的调用顺序
为了更直观地理解两者的执行顺序,我们来看一张经典的流程图:
HTTP Request
↓
Filter Chain(doFilter)
↓
DispatcherServlet
↓
Interceptor.preHandle
↓
Controller Method
↓
Interceptor.postHandle
↓
View Rendering(如有)
↓
Interceptor.afterCompletion
↓
Filter Chain(返回响应)
从这个流程可以看出:
- 过滤器 是最外层的"大门",所有请求都必须经过它。
- 拦截器 是内层的"小门",只对进入 Spring MVC 的请求生效。
三、实战演练:代码说话最真实
3.1 过滤器(Filter)实战:记录请求耗时
java
@Component
public class LogFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(LogFilter.class);
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
long startTime = System.currentTimeMillis();
HttpServletRequest httpRequest = (HttpServletRequest) request;
logger.info("请求开始,URI: {}", httpRequest.getRequestURI());
chain.doFilter(request, response); // 放行请求
long duration = System.currentTimeMillis() - startTime;
logger.info("请求结束,耗时: {}ms", duration);
}
}
3.2 拦截器(Interceptor)实战:登录权限校验
java
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Autowired
private AuthService authService; // 可以注入Spring Bean
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (!authService.isValidToken(token)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false; // 拦截请求
}
return true; // 放行请求
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
logger.info("Controller 方法执行完毕,准备渲染视图");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
logger.info("请求处理完成,资源清理");
}
}
3.3 配置拦截器到Spring容器
java
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/api/**") // 拦截所有 /api 开头的请求
.excludePathPatterns("/api/login"); // 排除登录接口
}
}
四、选型指南:什么时候用过滤器,什么时候用拦截器?
场景需求 | 推荐方案 |
---|---|
需要处理静态资源(如HTML、CSS、JS) | 过滤器(Filter) |
需要最早拦截请求(如全局跨域处理) | 过滤器(Filter) |
需要访问Spring Bean(如Service、Repository) | 拦截器(Interceptor) |
需要精确控制Controller方法的执行前后 | 拦截器(Interceptor) |
需要修改请求和响应的内容(如压缩、编码) | 过滤器(Filter) |
五、常见误区与最佳实践
5.1 常见误区
-
误区1:拦截器可以处理静态资源
实际上,拦截器默认不会拦截静态资源,除非你手动配置了
addResourceHandler
。 -
误区2:过滤器可以直接使用Spring Bean
过滤器由Servlet容器管理,默认无法使用Spring的依赖注入。可以通过
DelegatingFilterProxy
桥接,但配置较复杂。 -
误区3:拦截器可以修改请求参数
拦截器无法直接修改请求参数,如需修改,需使用过滤器配合
HttpServletRequestWrapper
。
5.2 最佳实践
- 优先使用拦截器:除非必须处理静态资源或需要最早拦截,否则优先使用拦截器,因为它更贴近业务逻辑,且易于测试。
- 避免复杂逻辑:无论是过滤器还是拦截器,都应避免复杂的业务逻辑,以免影响性能。
- 合理配置顺序:如果同时使用多个过滤器或拦截器,务必注意它们的执行顺序,避免逻辑冲突。
六、总结:一句话记住它们的区别
过滤器(Filter)是 Servlet 的"大门",拦截器(Interceptor)是 Spring MVC 的"小门"。
- Filter:更早、更底层、更通用,但离业务逻辑较远。
- Interceptor:更晚、更上层、更灵活,更贴近业务逻辑。