大数跨境
0
0

惊了!Spring Boot 拦截器竟藏着这些隐藏玩法,很强

惊了!Spring Boot 拦截器竟藏着这些隐藏玩法,很强 Spring全家桶实战案例
2025-06-04
0
导读:惊了!Spring Boot 拦截器竟藏着这些隐藏玩法,很强
Spring Boot 3实战案例锦集PDF电子书已更新至100篇!

🎉🎉《Spring Boot实战案例合集》目前已更新126个案例,我们将持续不断的更新。文末有电子书目录。

💪💪永久更新承诺

我们郑重承诺,所有订阅合集的粉丝都将享受永久免费的后续更新服务

💌💌如何获取
订阅我们的合集点我订阅,并通过私信联系我们,我们将第一时间将电子书发送给您。

→ 现在就订阅合集

环境:SpringBoot3.4.2



1. 简介

拦截器是什么?

拦截器是 Spring MVC 的一部分,在 Spring 框架内部工作。它允许针对控制器(Controller)专门修改请求和响应。

什么时候应该使用拦截器?

当需要 Spring 特有的逻辑时,可以使用拦截器,例如:

  • 认证与授权:为控制器验证用户凭据和权限

  • 记录执行时间:测量并跟踪控制器处理请求所需的时间

  • 修改模型/视图:在向客户端发送响应之前调整模型或视图

  • 添加通用属性:在所有响应中包含共享数据(例如,用户详细信息)

如何实现拦截器?

下面是一个非常简单的拦截器,紧紧是打印了一句话。

public class DemoInterceptor implements HandlerInterceptor {  @Override  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {    System.err.println("preHandle...") ;    return true ;  }  @Override  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,      ModelAndView modelAndView) throws Exception {    System.err.println("postHandle...") ;  }  @Override  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)      throws Exception {    System.err.println("afterCompletion...") ;  }}

接下来,还需要通过如下方式注册拦截器:

@Componentpublic class DemoConfig implements WebMvcConfigurer {  @Override  public void addInterceptors(InterceptorRegistry registry) {    registry.addInterceptor(new DemoInterceptor())      .addPathPatterns("/api/*") ;  }}

当我们请求以/api开头的请求时,将会执行上面拦截器对应的回调方法,如下:

preHandle...api query...postHandle...afterCompletion...

以上是拦截器从定义、注册到最终工作的整个流程。而在工作中基本我们也是这样去使用的。

而在本篇文章中,我们将介绍其它你不知道的高级玩法。

2.实战案例

2.1 拦截器包装器

Spring内部还提供了一个 MappedInterceptor,是一个包装类,它通过 URL 模式(URL patterns)来判断自身是否适用于给定的请求。该类最大的好处是与AbstractHandlerMethodMapping关联,会自动从当前容器中查找该类型的Bean。

首先,定义拦截器:

public class AuthInterceptor implements HandlerInterceptor {  private final static Logger logger = LoggerFactory.getLogger(AuthInterceptor.class) ;
  @Override  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {    logger.info("权限验证...") ;    return true ;  }}

接下来,通过MappedInterceptor注册:

@BeanMappedInterceptor authInterceptor(  @Value("${pack.auth.patterns}"String[] includePatterns) {  return new MappedInterceptor(includePatterns, new AuthInterceptor()) ;}

这样我们就完成了拦截器的注册。

2.2 全局拦截器

我们可以通过继承 AbstractHandlerMapping 类并实现其相关方法,来为应用中的所有请求统一添加拦截器,以此实现对请求处理流程的集中控制与扩展。 

@Componentpublic class PackHandlerMapping extends RequestMappingHandlerMapping {  // 获取容器中所有的拦截器  private final List<HandlerInterceptor> interceptors ;  public PackHandlerMapping(List<HandlerInterceptor> interceptors) {    this.interceptors = interceptors ;  }  @Override  protected void extendInterceptors(List<Object> interceptors) {    List<HandlerInterceptor> ret = this.interceptors.stream()        // 我们必须要进行过滤,否则拦截器将会执行两次        .filter(interceptor -> !(interceptor instanceof MappedInterceptor))        .collect(Collectors.toList()) ;    interceptors.addAll(ret) ;  }
  @Override  public int getOrder() {    return Ordered.HIGHEST_PRECEDENCE ;  }}

通过重写父类的extendInterceptors方法,这样我们就为所有的请求添加了拦截器。通过此种方式添加的拦截器不会匹配当前的请求uri。

下面,我们定义如下的拦截器:

@Componentpublic class LoggingInterceptor implements HandlerInterceptor {  private final static Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class) ;
  @Override  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {    logger.info("记录日志...") ;    return true ;  }}

这样所有被AbstractHandlerMapping映射器匹配的请求都会执行上面的拦截器。

2.3 异步拦截器

Spring MVC提供了一个AsyncHandlerInterceptor,该异步拦截器新增了一个方法在异步请求处理开始后被调用的回调方法afterConcurrentHandlingStarted。

当处理器启动异步请求时,DispatcherServlet 会直接退出,而不会像处理同步请求那样调用 postHandle 和 afterCompletion 方法。这是因为异步请求的处理结果(例如 ModelAndView)可能尚未就绪,且将由另一个线程并发生成。在此类场景下,会调用 afterConcurrentHandlingStarted 方法,允许拦截器实现类在释放线程给 Servlet 容器之前执行清理线程绑定属性等任务。

当异步处理完成后,请求会被重新分派到容器进行进一步处理。此时,DispatcherServlet 会再次调用 preHandle、postHandle 和 afterCompletion 方法。如下示例:

@Componentpublic class AsyncLogInterceptor implements AsyncWebRequestInterceptor {  // 请求一开始会执行一次  public void preHandle(WebRequest request) throws Exception {    System.err.printf("AsyncWebRequestInterceptor >>> %s, %s, 开始处理%n", System.currentTimeMillis(), Thread.currentThread().getName()) ;  }  // 当异步请求结束时执行  public void postHandle(WebRequest request, ModelMap model) throws Exception {    System.err.printf("AsyncWebRequestInterceptor >>> %s, postHandle%n", Thread.currentThread().getName()) ;  }  // 当异步请求结束时执行  public void afterCompletion(WebRequest request, Exception ex) throws Exception {    System.err.printf("AsyncWebRequestInterceptor >>> %s afterCompletion%n", Thread.currentThread().getName()) ;  }  // 异步请求开始时执行  public void afterConcurrentHandlingStarted(WebRequest request) {    System.err.printf("AsyncWebRequestInterceptor >>> %s, %s, 异步处理%n", System.currentTimeMillis(), Thread.currentThread().getName()) ;  }}

注册拦截器

@Componentpublic class WebInterceptorConfig implements WebMvcConfigurer{
  public void addInterceptors(InterceptorRegistry registry) {    registry.addWebRequestInterceptor(new AsyncLogInterceptor())      .addPathPatterns("/admin/**") ;  }}

定义Controller接口

@GetMapping("/async")public Callable<Stringasync() {  return new Callable<String>() {    public String call() throws Exception {      System.err.printf("%s, %s - 执行任务%n", System.currentTimeMillis(), Thread.currentThread().getName()) ;      TimeUnit.SECONDS.sleep(3) ;      return "异步数据" ;    }  };}

最终输出结果如下:


以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏

推荐文章

Spring Boot 通过 6 种方式实现开关功能,最后一种直接封神

太强了!Spring Boot 五大内置 "神兵" 工具

技术专家!Spring Boot 运行时动态修改执行SQL,支持JPA,MyBatis,JDBC

太赞了!AOP弃用@Aspect,一个注解让你的代码灵活十倍!

高级开发!性能优化,Spring Boot 不使用AOP也能优雅的记录日志

王炸!Spring AI+MCP 三步实现智能体开发

生产环境修改Spring Boot配置文件不重启也能实时生效

强大!基于Map优化缓存设计

优雅!Spring 基于 Plugin 插件开发(官方推荐)

高级开发!Spring Boot 乐观锁正确处理的3种方案,第三种方案最优雅

告别内存溢出!Spring StreamingResponseBody 三大实战案例,性能提升100%

【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读7
粉丝0
内容832