一、理解核心概念
在 Java Web 开发中,**过滤器(Filter)和拦截器(Interceptor)**是两种核心的请求处理机制。它们虽然都能对请求进行拦截和处理,但定位截然不同:
- Filter 是 Servlet 容器的'守门人',位于应用最外层
- Interceptor 是 Spring MVC 的'执法官',位于框架内部
二、Filter:Servlet 容器的第一道防线
2.1 本质与特点
Filter 是 Java Servlet 规范 定义的组件,由 Servlet 容器(如 Tomcat)直接管理,不依赖任何框架,因此具有最强的通用性。
生命周期方法:
| 方法 | 触发时机 | 用途 |
|---|---|---|
init() | 应用启动时 | 初始化配置 |
doFilter() | 每次请求 | 核心处理逻辑 |
destroy() | 应用关闭时 | 资源释放 |
执行流程:
请求 → Filter1 → Filter2 → Servlet/Controller → Filter2 → Filter1 → 响应
2.2 Spring Boot 中的实现方式
方式一:注解方式(适合简单场景)
@WebFilter(urlPatterns = "/api/*", filterName = "authFilter")
public class AuthFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 前置处理
System.out.println("认证检查开始");
// 放行到下一个 Filter 或目标资源
chain.doFilter(request, response);
// 后置处理(响应返回时执行)
System.out.println("认证检查结束");
}
}
// 在主类开启扫描
@SpringBootApplication
@ServletComponentScan
public class Application {
}
方式二:配置类方式(推荐,更灵活)
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<AuthFilter> authFilter() {
FilterRegistrationBean<AuthFilter> bean = new FilterRegistrationBean<>();
bean.setFilter(new AuthFilter());
bean.addUrlPatterns("/api/*");
bean.setOrder(1); // 控制执行顺序,数字越小越先执行
return bean;
}
}
2.3 Filter 的典型应用场景
| 场景 | 说明 |
|---|---|
| 统一编码 | 设置 UTF-8 编码,解决中文乱码 |
| 安全防护 | XSS 过滤、SQL 注入检测 |
| 跨域处理 | 添加 CORS 响应头 |
| 请求日志 | 记录所有请求的 IP、路径、耗时 |
| 数据压缩 | Gzip 压缩响应内容 |
三、Interceptor:Spring MVC 的精准拦截
3.1 本质与特点
Interceptor 是 Spring MVC 框架 提供的机制,只能拦截被 DispatcherServlet 处理的请求(即映射到 Controller 的请求)。它可以获取 Spring 上下文,与业务逻辑深度集成。
三个核心拦截点:
| 方法 | 执行时机 | 能否终止请求 | 典型用途 |
|---|---|---|---|
preHandle() | Controller 方法执行前 | 可返回 false 终止 | 登录验证、权限校验 |
postHandle() | Controller 执行后,视图渲染前 | 无法终止 | 修改 Model、添加公共数据 |
afterCompletion() | 请求处理完成(含异常) | 无法终止 | 资源清理、异常日志 |
3.2 完整实现示例
@Component
public class PermissionInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 获取请求信息
String uri = request.getRequestURI();
System.out.println("【拦截】请求路径:" + uri);
// 权限校验逻辑
HttpSession session = request.getSession();
if (session.getAttribute("user") == null && uri.startsWith("/admin")) {
response.sendRedirect("/login");
return false; // 拦截,不继续执行
}
return true; // 放行
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// 向视图添加通用数据
if (modelAndView != null) {
modelAndView.addObject("serverTime", new Date());
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) throws Exception {
// 记录异常信息
if (ex != null) {
System.out.println("【异常】请求处理出错:" + ex.getMessage());
}
// 清理 ThreadLocal 等资源
}
}
注册 Interceptor:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private PermissionInterceptor permissionInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(permissionInterceptor)
.addPathPatterns("/admin/**", "/user/**") // 拦截路径
.excludePathPatterns("/login", "/public/**"); // 排除路径
}
}
四、核心区别对比
| 对比维度 | Filter | Interceptor |
|---|---|---|
| 规范来源 | Servlet 规范(J2EE) | Spring MVC 框架 |
| 框架依赖 | 不依赖 Spring,任何 Web 应用可用 | 必须在 Spring 环境中使用 |
| 拦截范围 | 所有请求(含静态资源、JSP) | 仅 DispatcherServlet 映射的请求 |
| 执行时机 | Servlet 之前 | Controller 前后 |
| 方法数量 | 1 个 doFilter() | 3 个:preHandle、postHandle、afterCompletion |
| 可获取对象 | ServletRequest、ServletResponse | HttpServletRequest、HandlerMethod、ModelAndView |
| 异常处理 | 只能捕获 Filter 内部异常 | afterCompletion可捕获 Controller 异常 |
| 静态资源拦截 | 支持 | 默认不支持 |
五、执行顺序详解
当 Filter 和 Interceptor 同时存在时,执行流程如下:
1. Filter.doFilter() 前置代码 ↓
2. Interceptor.preHandle() ↓
3. Controller 方法执行 ↓
4. Interceptor.postHandle() ↓
5. 视图渲染 ↓
6. Interceptor.afterCompletion() ↓
7. Filter.doFilter() 后置代码
示意图:
请求进入 ↓
[Filter 1] ──┐
↓ │
[Filter 2] │ 过滤器链(双向拦截)
↓ │
[Servlet] │
↓ │
[Interceptor 1.preHandle] ──┐
↓ │
[Interceptor 2.preHandle] │
↓ │
[Controller 执行] │ 拦截器链(三阶段)
↓ │
[Interceptor 2.postHandle] │
↓ │
[Interceptor 1.postHandle] │
↓ │
[视图渲染] │
↓ │
[Interceptor 1.afterCompletion]┘
↓ [Interceptor 2.afterCompletion]
↓ [Filter 2 后置]
↓ [Filter 1 后置]
↓ 响应返回
六、实战选择指南
6.1 优先使用 Filter 的场景
- 统一字符编码:需要在请求进入 Servlet 前就设置编码
- 跨域处理(CORS):处理
OPTIONS预检请求,早于 Spring MVC - 安全过滤:XSS、SQL 注入的输入预处理
- 全局日志:记录所有 HTTP 请求的完整生命周期
- 非 Spring 环境:纯 Servlet 应用
6.2 优先使用 Interceptor 的场景
- 登录状态校验:可便捷获取
HttpSession和 Spring Bean - 细粒度权限控制:结合
@PreAuthorize、Security 上下文 - 性能监控:精确统计 Controller 执行时间
- 业务操作日志:获取
HandlerMethod知道调用了哪个方法 - 视图数据增强:在
postHandle中向 Model 添加数据
七、黄金组合实践
在实际项目中,两者配合使用才能发挥最大价值:
| 层级 | 组件 | 职责 |
|---|---|---|
| 外层 | Filter | 编码设置、CORS、XSS 过滤、请求日志 |
| 内层 | Interceptor | 登录验证、权限校验、性能监控、业务日志 |
典型配置示例:
// Filter 处理通用底层逻辑
@Bean
public FilterRegistrationBean<CharacterEncodingFilter> encodingFilter() {
FilterRegistrationBean<CharacterEncodingFilter> bean = new FilterRegistrationBean<>();
bean.setFilter(new CharacterEncodingFilter("UTF-8", true));
bean.addUrlPatterns("/*");
bean.setOrder(Ordered.HIGHEST_PRECEDENCE); // 最先执行
return bean;
}
// Interceptor 处理业务逻辑
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthInterceptor())
.addPathPatterns("/api/**")
.excludePathPatterns("/api/login");
}
八、面试高频问题
Q1:Filter 和 Interceptor 的本质区别是什么?
Filter 是 Servlet 规范,由容器管理;Interceptor 是 Spring MVC 机制,由框架管理。Filter 更早执行,能拦截所有请求;Interceptor 更晚执行,只能拦截 Spring MVC 请求,但能获取更丰富的上下文。
Q2:如何让 Interceptor 拦截静态资源?
修改 DispatcherServlet 的 url-pattern 为 /*,但会带来性能开销,通常不建议。静态资源拦截建议用 Filter。
Q3:afterCompletion 一定会执行吗?
只要 preHandle 返回 true 并执行了,无论后续是否异常,afterCompletion 都会执行,适合资源清理。
Q4:如何控制多个 Filter 的执行顺序?
使用 FilterRegistrationBean 的 setOrder() 方法,数字越小优先级越高。
九、总结
| Filter | Interceptor | |
|---|---|---|
| 定位 | 容器层'护城河' | 框架层'城门守卫' |
| 优势 | 通用、底层、无框架依赖 | 精细、灵活、可获取 Spring 上下文 |
| 最佳实践 | 处理通用、底层问题 | 处理业务、安全、监控逻辑 |
核心原则:Filter 做'通用处理',Interceptor 做'业务拦截',两者协同构建完整的请求处理体系。

