⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 小哈学Java 「犬小哈」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

面试考察点

面试官提出这个问题,主要想考察以下几个层面的理解:

  1. 对技术栈层次的清晰认知:你是否能清晰区分 Servlet 规范(Java EE/ Jakarta EE 标准)和 Spring 框架(具体实现)的边界。
  2. 对 Web 请求处理流程的深入理解:你是否了解一个 HTTP 请求到达应用后,经过的完整处理链条,以及不同组件在这个链条上的具体位置和作用。
  3. 对组件职责和适用场景的把握:不仅仅是记忆区别,更想知道你能否根据不同的业务需求(如安全、日志、性能监控)做出正确的技术选型。
  4. 对实现原理和扩展性的了解:你是否了解它们的底层实现机制(如动态代理),以及如何进行定制和扩展。

核心答案

过滤器 (Filter) 是 Servlet 规范的一部分,作用于 Web 容器 层面。它在请求进入 Servlet 之前和响应离开 Servlet 之后工作,主要对请求/响应的内容进行粗粒度的预处理和后处理,如编码设置、全局日志、跨域处理。

拦截器 (Interceptor) 是 Spring MVC 框架的一部分,作用于 Spring 上下文 层面。它在请求进入 DispatcherServlet 之后,在具体的 Controller 方法执行前、后以及渲染完视图后(afterCompletion)介入,主要对请求进行细粒度的、与业务逻辑更相关的处理,如权限校验、日志审计、性能监控。

核心区别一句话:过滤器是 Servlet 的 “门卫”,拦截器是 Spring MVC 的 “安检员”。

深度解析

原理/机制

过滤器 (Filter) 基于 Servlet 规范 的 Filter 接口,其工作完全由 Web 容器(如 Tomcat)管理。它通过 FilterChain 进行链式调用,与任何框架无关。

拦截器 (Interceptor) 基于 Spring AOP(面向切面编程) 和 动态代理 机制实现。它实现了 HandlerInterceptor 接口,由 Spring 的 DispatcherServlet 在内部流程中调用,因此天然可以获取到 Spring 上下文中的所有 Bean,并深度参与 MVC 流程。

代码示例

1. 过滤器实现示例

// 实现 javax.servlet.Filter (Jakarta EE 9+) 或 javax.servlet.Filter (Java EE 8)
@Component// 让 Spring 管理其生命周期,并通过 FilterRegistrationBean 注册
@Order(1) // 定义执行顺序
publicclassLoggingFilterimplementsFilter{
@Override
publicvoiddoFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
long startTime = System.currentTimeMillis();

// 1. 在请求到达 Servlet 前执行 (预处理)
System.out.println("Filter: Request URI - " + httpRequest.getRequestURI());

chain.doFilter(request, response); // 放行,传递给下一个过滤器或最终的 Servlet

// 2. 在响应返回客户端前执行 (后处理)
long duration = System.currentTimeMillis() - startTime;
System.out.println("Filter: Request processed in " + duration + " ms");
}
}

2. 拦截器实现示例

// 实现 org.springframework.web.servlet.HandlerInterceptor
@Component
publicclassAuthInterceptorimplementsHandlerInterceptor{

// 在 Controller 方法执行前调用
@Override
publicbooleanpreHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String token = request.getHeader("Authorization");
if (!isValidToken(token)) {
response.sendError(HttpStatus.UNAUTHORIZED.value(), "Invalid token");
returnfalse; // 中断执行链,不再调用后续拦截器和 Controller
}
returntrue; // 继续执行
}

// 在 Controller 方法执行后,视图渲染前调用
@Override
publicvoidpostHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView)throws Exception {
// 可以对 ModelAndView 进行修改
}

// 在整个请求完成(视图渲染完毕)后调用,常用于资源清理
@Override
publicvoidafterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex)throws Exception {
// 记录请求完成,或处理异常
}
}

// 注册拦截器到 WebMvcConfigurer
@Configuration
publicclassWebConfigimplementsWebMvcConfigurer{
@Autowired
private AuthInterceptor authInterceptor;

@Override
publicvoidaddInterceptors(InterceptorRegistry registry){
registry.addInterceptor(authInterceptor)
.addPathPatterns("/api/**") // 配置拦截路径
.excludePathPatterns("/api/public/**"); // 配置排除路径
}
}

对比分析与最佳实践

维度 过滤器 (Filter) 拦截器 (Interceptor)
归属与规范 Servlet 规范 (J2EE/Jakarta EE) Spring 框架
实现原理 基于 Servlet 容器的 FilterChain 基于 Spring AOP 和动态代理
触发时机 最早 和 最晚。在请求进入 Servlet前,响应离开 Servlet后。 在请求进入 DispatcherServlet之后。preHandle (Controller 前), postHandle (Controller 后), afterCompletion (视图渲染后)
作用范围 对所有进入容器的请求生效(包括静态资源) 只对 Spring MVC 管理的请求生效(即经过 DispatcherServlet 的请求)
获取上下文 只能获取 ServletContext 可以获取 Spring 的 ApplicationContext 和所有 Bean
处理对象 ServletRequest 和 ServletResponse HttpServletRequest, HttpServletResponse, HandlerMethod (可以获取方法、参数等元信息)
异常处理 在 Filter 中抛出的异常,可以在 web.xml 或 @ControllerAdvice之外 配置错误页面。 在 Interceptor 中抛出的异常,可以被 Spring 的 @ControllerAdvice全局异常处理器 捕获。

最佳实践与选择依据:

  • 使用过滤器:当你需要处理的是与具体业务无关的、全局性的、底层的请求/响应处理时。例如:

    • 设置全局字符编码 (CharacterEncodingFilter)
    • 跨域资源共享 (CorsFilter)
    • 压缩响应内容 (GzipFilter)
    • 防止 XSS 攻击的请求参数过滤
  • 使用拦截器:当你需要处理的是与业务逻辑紧密相关、依赖于 Spring 环境 的处理时。例如:

    • 用户登录状态与权限校验
    • 审计日志(记录谁在什么时间访问了哪个方法)
    • 接口性能监控(精确到 Controller 方法级别)
    • 通用的参数预处理或后处理

常见误区

  1. 认为过滤器是 Spring 特有的:这是一个常见误解。过滤器是 Java Web 标准,即使不使用 Spring,纯 Servlet 项目也能用。
  2. 不清楚执行顺序:在一个请求中,如果同时存在多个过滤器和拦截器,其执行顺序为:Filter -> DispatcherServlet -> Interceptor.preHandle -> Controller -> Interceptor.postHandle -> 渲染视图 -> Interceptor.afterCompletion -> Filter。
  3. 在过滤器中试图注入 Spring Bean 失败:如果 Filter 由容器(如 Tomcat)直接实例化,则 @Autowired 会失效。解决方案是使用 DelegatingFilterProxy(Spring Boot 默认配置)或让 Filter 本身成为一个 Spring Bean(如上面示例所示,并用 FilterRegistrationBean 注册)。

总结

过滤器是 Web 容器的标准组件,作用于更底层,适合处理全局性、协议相关的任务;拦截器是 Spring MVC 的框架组件,深度集成于 Spring 上下文,适合处理与业务逻辑密切相关的横切关注点。理解它们的差异和适用场景,是构建清晰、可维护的 Web 应用架构的基础。

文章目录
  1. 1. 面试考察点
  2. 2. 核心答案
  3. 3. 深度解析
    1. 3.1. 原理/机制
    2. 3.2. 代码示例
    3. 3.3. 对比分析与最佳实践
    4. 3.4. 常见误区
  4. 4. 总结