Spring Boot 拦截器使用全指南
- 发布时间:2025-11-18 17:30:13
- 本文热度:浏览 7 赞 0 评论 0
- 文章标签: Spring Boot Java 拦截器
- 全文共1字,阅读约需1分钟
1. Spring Boot 拦截器概念与核心思想
1.1 拦截器是什么
拦截器(Interceptor)是 Spring 框架提供的一种处理机制,用于在请求到达 Controller 之前或之后执行特定逻辑。它类似于 Servlet Filter,但功能更强大,能够获取 Spring MVC 的上下文,并操作请求和响应对象。
拦截器的核心特点:
- 链式调用:多个拦截器按顺序执行,前一个拦截器决定是否调用下一个。
- 面向请求处理:拦截器主要作用于 Controller 层,处理请求和响应。
- 灵活配置:可根据 URL、请求方法或条件配置拦截路径。
1.2 为什么需要拦截器
拦截器解决了很多通用需求,例如:
- 身份认证与权限校验:请求到达 Controller 前验证用户身份。
- 日志记录:记录访问日志、操作日志。
- 性能监控:统计请求耗时。
- 请求统一处理:如添加通用响应头、设置请求属性等。
1.3 拦截器与过滤器区别
| 特性 | 拦截器 (Interceptor) | 过滤器 (Filter) |
|---|---|---|
| 生命周期 | Spring 容器管理 | Servlet 容器管理 |
| 功能范围 | Controller 层 | 所有请求,包括静态资源 |
| 可以访问 | Spring MVC 上下文、Handler | 原生 HttpServletRequest、HttpServletResponse |
| 配置方式 | WebMvcConfigurer 添加 | web.xml 或 @WebFilter 注解 |
作者经验总结:拦截器与过滤器各有适用场景,拦截器更适合与 Spring MVC 深度集成,推荐用于业务层统一处理逻辑,过滤器适合全局请求控制或跨框架拦截。
2. 拦截器工作原理与执行流程
2.1 核心执行流程
Spring MVC 拦截器主要依赖 HandlerInterceptor 接口,执行流程如下:
客户端请求 → DispatcherServlet → HandlerMapping → HandlerInterceptor.preHandle
→ Controller → HandlerInterceptor.postHandle
→ ViewResolver → DispatcherServlet → HandlerInterceptor.afterCompletion → 响应客户端
三个关键方法:
-
preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)- 在 Controller 方法执行前调用
- 返回
true表示继续执行,返回false阻止请求继续处理
-
postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)- Controller 方法执行后,渲染视图前调用
- 可修改 ModelAndView,添加通用数据
-
afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)- 请求处理完成后调用(无论是否异常)
- 常用于清理资源、日志记录、性能统计
2.2 图示思维
┌─────────────┐
│ Client │
└───────┬─────┘
│
▼
┌─────────────┐
│ Dispatcher │
│ Servlet │
└───────┬─────┘
│
▼
┌────────────────────┐
│ HandlerInterceptor │
│ preHandle │
└────────┬───────────┘
│ true
▼
┌─────────────┐
│ Controller │
└───────┬─────┘
│
▼
┌────────────────────┐
│ HandlerInterceptor │
│ postHandle │
└────────┬───────────┘
▼
┌─────────────┐
│ View │
└───────┬─────┘
▼
┌────────────────────┐
│ HandlerInterceptor │
│ afterCompletion │
└────────────────────┘
▼
Response
作者经验总结:理解拦截器的执行顺序是关键,特别是 preHandle 决定请求是否继续,postHandle 可修改返回结果,afterCompletion 用于收尾工作。
3. Spring Boot 拦截器配置与实现
3.1 创建自定义拦截器
实现 HandlerInterceptor 接口或继承 HandlerInterceptorAdapter(Spring 5 已废弃 HandlerInterceptorAdapter,推荐直接实现接口)。
package com.example.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class LogInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("请求开始:" + request.getRequestURI());
return true; // 继续执行请求
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("请求处理完成,渲染视图前执行");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
System.out.println("请求完成,清理资源");
}
}
3.2 注册拦截器
在 Spring Boot 中,需要通过实现 WebMvcConfigurer 配置拦截器。
package com.example.config;
import com.example.interceptor.LogInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor())
.addPathPatterns("/**") // 拦截所有请求
.excludePathPatterns("/login", "/static/**"); // 排除部分请求
}
}
3.3 注意事项
- 顺序问题:多个拦截器按注册顺序执行。
- 静态资源:需排除
/static/**,否则 CSS、JS、图片请求也会被拦截。 - 返回值控制:
preHandle返回false会直接结束请求。
作者经验总结:在实际项目中,拦截器注册要分清通用拦截器与特定业务拦截器,避免影响静态资源和外部接口。
4. 实战案例:统一登录认证拦截器
4.1 需求分析
- 所有请求需要登录验证
- 未登录用户返回 JSON 提示
- 登录状态保存在 Session 或 Redis
4.2 实现思路
preHandle检查请求头或 Session 中的登录状态- 未登录返回 JSON
- 登录则继续执行 Controller
4.3 代码示例
package com.example.interceptor;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
public class AuthInterceptor implements HandlerInterceptor {
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object user = request.getSession().getAttribute("user");
if (user == null) {
response.setContentType("application/json;charset=UTF-8");
Map<String, Object> result = new HashMap<>();
result.put("code", 401);
result.put("msg", "未登录");
PrintWriter writer = response.getWriter();
writer.write(objectMapper.writeValueAsString(result));
writer.flush();
return false;
}
return true;
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/login", "/register", "/static/**");
}
}
作者经验总结:统一认证拦截器可以极大减少 Controller 中重复代码,但要注意排除登录、注册等公共接口,避免循环拦截。
5. 高级用法与扩展
5.1 拦截器传递参数
可以通过 request.setAttribute 在 preHandle 设置数据,Controller 或 postHandle 可直接读取。
request.setAttribute("startTime", System.currentTimeMillis());
在 afterCompletion 统计耗时:
long start = (Long) request.getAttribute("startTime");
long duration = System.currentTimeMillis() - start;
System.out.println("请求耗时:" + duration + "ms");
5.2 异步请求拦截器
对于异步请求(@Async 或 Callable),preHandle 依旧先执行,但 postHandle 可能延迟,需要结合 DeferredResult 或 CompletableFuture 处理。
5.3 全局异常与拦截器结合
拦截器的 afterCompletion 方法可捕获异常对象 ex,用于统一日志和监控:
if (ex != null) {
System.err.println("请求异常:" + ex.getMessage());
}
作者经验总结:拦截器不仅能做权限控制,也适合做全局日志、性能监控和异常收集,结合 AOP 可实现更精细化业务逻辑。
6. 常见错误与排查方法
| 错误场景 | 可能原因 | 解决方案 |
|---|---|---|
| 拦截器未生效 | 未注册到 WebMvcConfigurer | 检查配置类是否加 @Configuration,addInterceptors 是否调用 |
| 静态资源被拦截 | addPathPatterns 拦截了 /static/** |
使用 excludePathPatterns 排除静态资源路径 |
| preHandle 返回 false,但 Controller 仍执行 | 返回 false 前未正确中断流 | 确认 preHandle 中 return false 后没有调用 response.sendRedirect 或继续链 |
| 顺序不符合预期 | 多个拦截器注册顺序 | 调整 registry.addInterceptor 顺序 |
| 异步请求日志异常 | postHandle 不适用异步 | 使用 afterCompletion 或结合 AsyncListener |
作者经验总结:排查拦截器问题的核心是确认注册顺序、排除路径、返回值逻辑,以及异步场景下方法调用顺序。
7. 实践案例:访问日志与性能监控拦截器
7.1 需求分析
- 记录请求 URL、方法、用户信息
- 统计接口耗时
- 输出日志到控制台或日志系统
7.2 代码示例
package com.example.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
public class RequestLogInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
long start = System.currentTimeMillis();
request.setAttribute("startTime", start);
System.out.println("请求开始:" + request.getMethod() + " " + request.getRequestURI());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
long start = (Long) request.getAttribute("startTime");
long duration = System.currentTimeMillis() - start;
System.out.println("请求完成:" + request.getMethod() + " " + request.getRequestURI() + " 耗时:" + duration + "ms");
if (ex != null) {
System.err.println("请求异常:" + ex.getMessage());
}
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new RequestLogInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/static/**");
}
}
作者经验总结:这种拦截器适用于微服务监控、接口分析,可结合 ELK 或 Prometheus 收集数据,实现实时监控和告警。
8. 最佳实践总结
- 明确拦截器职责:每个拦截器只做一件事,如日志、权限、性能统计,避免过度耦合。
- 排除静态资源与公共接口:防止影响页面加载和外部 API。
- 尽量轻量:
preHandle和postHandle尽量快速,避免阻塞请求。 - 结合 AOP:复杂业务逻辑或异常处理可以通过 AOP 与拦截器结合。
- 日志规范化:输出可追踪的请求 ID,便于问题排查。
- 顺序控制:注册顺序决定执行顺序,注意链式逻辑。
9. 延伸阅读
- Spring MVC 官方文档关于
HandlerInterceptor的说明 - Spring Boot WebMvcConfigurer 拦截器注册技巧
- 异步请求与拦截器结合的最佳实践
- 与 AOP、Filter、Aspect 对比使用场景
- 性能优化与日志分析实践