Spring Boot 拦截器是处理横切关注点的最佳实践
在Spring Boot项目中,拦截器(Interceptor)是实现日志记录、权限校验、性能监控、请求预处理等需求的标配组件。 它通过AOP思想,在不侵入业务代码的前提下,对请求进行统一处理,配置拦截器主要分为三步:编写自定义拦截器类(实现HandlerInterceptor)、注册拦截器(实现WebMvcConfigurer)、指定拦截路径,掌握这一配置流程,能大幅提升代码复用性与系统可维护性。
拦截器的工作原理与定位
Spring Boot拦截器基于Java反射机制,在请求进入Controller前、后以及视图渲染完成后插入自定义逻辑。 其核心接口HandlerInterceptor包含三个方法:
preHandle:在Controller执行前调用,返回true表示继续执行,返回false则中断请求。postHandle:在Controller执行后、视图渲染前调用,可修改ModelAndView。afterCompletion:在请求完全结束后调用,常用于资源清理或日志记录。
拦截器与过滤器的区别:过滤器基于Servlet规范,可处理所有请求;拦截器基于Spring MVC,仅处理DispatcherServlet分发的请求,且能访问Spring容器中的Bean,更适合业务逻辑处理。
标准配置流程:三步走
实现自定义拦截器
创建一个类实现HandlerInterceptor接口,按需重写方法。
public class LogInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 记录请求开始时间

request.setAttribute("startTime", System.currentTimeMillis());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 计算并输出请求耗时
long duration = System.currentTimeMillis() - (long) request.getAttribute("startTime");
System.out.println("[" + request.getRequestURI() + "] 耗时:" + duration + "ms");
}
}
注册拦截器
通过实现WebMvcConfigurer并重写addInterceptors方法进行注册:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor())
.addPathPatterns("/") // 拦截所有请求
.excludePathPatterns("/login", "/static/"); // 排除登录页和静态资源
}
}
定制拦截路径
使用addPathPatterns和excludePathPatterns灵活控制拦截范围,支持Ant风格路径(如/api/匹配一级,/api/匹配多级)。
多拦截器的执行顺序与配合
当注册多个拦截器时,按添加顺序执行preHandle,按逆序执行postHandle和afterCompletion。
registry.addInterceptor(interceptorA).addPathPatterns("/");
registry.addInterceptor(interceptorB).addPathPatterns("/");
请求流程:A的preHandle→B的preHandle→Controller→B的postHandle→A的postHandle→B的afterCompletion→A的afterCompletion,若A的preHandle返回false,则B的preHandle及其后续方法均不执行。

实践建议:将权限校验拦截器放在首位,日志拦截器放在其后,确保权限不足时不会产生冗余日志。
典型应用场景与解决方案
统一权限校验
在preHandle中获取用户信息(如Token),验证权限,若未通过则返回401并设为false。
接口性能监控
结合preHandle记录开始时间,afterCompletion计算耗时,可配合酷番云云监控服务,将耗时数据实时上报,通过自定义监控面板可视化分析接口性能瓶颈。
请求日志记录
记录请求URL、IP、参数、响应状态等,但需注意敏感信息脱敏。
接口幂等性控制
在preHandle中检查请求唯一标识是否已处理,防止重复提交。
经验案例:酷番云环境下的日志拦截器优化
在酷番云部署的Spring Boot应用中,我们曾遇到日志量过大导致磁盘IO飙升的问题。 通过合理配置拦截器,并借助酷番云对象存储COS,我们实现了日志的异步归档:
- 拦截器收集请求摘要(耗时、状态码、URI),存入本地队列。
- 后台线程批量上传至COS,本地只保留短期索引。
- 利用酷番云日志服务(CLS)设置检索告警,当错误率超过阈值时自动通知。
优化后,应用日志对磁盘的消耗降低90%,同时通过云平台实现了日志的持久化与快速检索。 这一方案在多个生产环境中验证,稳定性与效率均大幅提升。
最佳实践与避坑指南
- 避免在拦截器中执行耗时操作,如数据库查询、远程调用,否则会阻塞请求线程,可改用异步处理或队列。
- 正确获取返回值:
preHandle返回false后,务必调用response.getWriter().write()或response.sendError(),否则客户端会一直等待。 - 静态资源路径需排除:Spring Boot默认静态资源路径(/static, /public, /resources, /META-INF/resources)应通过
excludePathPatterns跳过,避免拦截器干扰资源加载。 - 拦截器与异常处理结合:在
afterCompletion中捕获异常时,可结合@ControllerAdvice统一处理,避免重复记录。

问答模块
问题1:拦截器能否获取到Controller方法上的注解?
可以,在preHandle方法中,参数handler实际是HandlerMethod对象,可通过((HandlerMethod) handler).getMethodAnnotation(注解类.class)获取指定注解,实现一个自定义注解@RequirePermission,在拦截器中读取注解值并校验权限,无需硬编码URL。
问题2:高并发下拦截器内的异步操作会不会导致线程安全问题?
会。 拦截器默认运行在Tomcat工作线程中,若在preHandle中启动异步线程处理任务,需注意线程安全,建议使用@Async或AsyncTaskExecutor,并确保线程安全的数据结构(如ConcurrentHashMap),若在afterCompletion中处理异步结果,需谨慎处理请求上下文的传递。
互动
你在配置Spring Boot拦截器时遇到过哪些坑?或者有哪些独特的用法?欢迎在评论区分享经验,一起交流进步!
图片来源于AI模型,如侵权请联系管理员。作者:酷小编,如若转载,请注明出处:https://www.kufanyun.com/ask/657481.html


评论列表(3条)
这篇文章写得非常好,内容丰富,观点清晰,让我受益匪浅。特别是关于返回的部分,分析得很到位,给了我很多新的启发和思考。感谢作者的精心创作和分享,期待看到更多这样高质量的内容!
这篇文章的内容非常有价值,我从中学习到了很多新的知识和观点。作者的写作风格简洁明了,却又不失深度,让人读起来很舒服。特别是返回部分,给了我很多新的思路。感谢分享这么好的内容!
这篇文章的内容非常有价值,我从中学习到了很多新的知识和观点。作者的写作风格简洁明了,却又不失深度,让人读起来很舒服。特别是返回部分,给了我很多新的思路。感谢分享这么好的内容!