Salmon的全栈知识 Salmon的全栈知识
首页
  • JavaSE
  • JavaWeb
  • Spring生态
  • JUC
  • JVM
  • Netty
  • Java各版本特性
  • 23种设计模式
  • Maven
  • Java常用框架
  • Dubbo
  • OpenFeign
  • Nacos
  • Zookeeper
  • Sentinel
  • Seata
  • SpringCloud Gateway
  • Apollo
  • Eureka
  • Go基础
  • Gin
  • SQL数据库

    • MySQL
    • Oracle
  • NoSQL数据库

    • Redis
    • MongoDB
    • ElasticSearch
  • 消息中间件

    • RabbitMQ
    • RocketMQ
    • Kafka
    • ActiveMQ
    • MQTT
    • NATS
  • 网关中间件

    • Nginx
  • Linux
  • Docker
  • Git
  • K8s
  • Solidity
  • Java
  • 计算机网络
  • 操作系统
GitHub (opens new window)
首页
  • JavaSE
  • JavaWeb
  • Spring生态
  • JUC
  • JVM
  • Netty
  • Java各版本特性
  • 23种设计模式
  • Maven
  • Java常用框架
  • Dubbo
  • OpenFeign
  • Nacos
  • Zookeeper
  • Sentinel
  • Seata
  • SpringCloud Gateway
  • Apollo
  • Eureka
  • Go基础
  • Gin
  • SQL数据库

    • MySQL
    • Oracle
  • NoSQL数据库

    • Redis
    • MongoDB
    • ElasticSearch
  • 消息中间件

    • RabbitMQ
    • RocketMQ
    • Kafka
    • ActiveMQ
    • MQTT
    • NATS
  • 网关中间件

    • Nginx
  • Linux
  • Docker
  • Git
  • K8s
  • Solidity
  • Java
  • 计算机网络
  • 操作系统
GitHub (opens new window)
npm

(进入注册为作者充电)

  • Spring框架

    • 传统Javaweb开发的困惑
    • IoC、DI和AOP思想提出
    • Spring框架的诞生
    • 基于xml的Spring应用
    • 基于注解的Spring应用
    • AOP 简介
    • 基于xml配置的AOP
    • 基于注解配置的AOP
    • 基于AOP的声明式事务控制
  • SpringMVC框架

    • Spring整合web环境
    • web层MVC框架思想与设计思路
    • SpringMVC简介
    • SpringMVC的请求处理
    • SpringMVC的响应处理
    • SpringMVC的拦截器
      • 1、拦截器 Interceptor 简介
      • 2、拦截器快速入门
      • 3、拦截器执行顺序
      • 4、拦截器执行原理
    • SpringMVC的全注解开发
    • SpringMVC的组件原理剖析
    • SpringMVC的异常处理机制
  • 《Spring生态》笔记
  • SpringMVC框架
Salmon
2025-07-23
目录

SpringMVC的拦截器

# 1、拦截器 Interceptor 简介

SpringMVC的拦截器Interceptor规范,主要是对Controller资源访问时进行拦截操作的技术,当然拦截后可以进行权限控制,功能增强等都是可以的。拦截器有点类似 Javaweb 开发中的Filter,拦截器与Filter的区别如下图:

image-20250729004730802

由上图,对Filter 和 Interceptor 做个对比:

比较维度 Filter 技术(过滤器) Interceptor 技术(拦截器)
技术范畴 JavaWeb 原生技术 SpringMVC 框架技术
拦截/过滤资源 可对所有请求进行过滤,包括 Servlet、JSP、静态资源等 仅拦截进入 SpringMVC 的请求(即 Controller 请求)
执行时机 在任何 Servlet 执行之前 在 DispatcherServlet 之后执行

实现了HandlerInterceptor接口,且被Spring管理的Bean都是拦截器,接口定义如下:

public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }

    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

HandlerInterceptor接口方法的作用及其参数、返回值详解如下:

方法名 作用说明 参数说明 返回值说明
preHandle 对拦截到的请求进行预处理,返回 true 表示放行,false 表示终止请求 Handler:拦截到的 Controller 方法处理器 boolean:返回 false,请求终止,所有后置方法不执行返回 true,继续执行流程
postHandle Controller 方法执行后,视图渲染前进行后处理,可修改模型数据与视图 Handler:拦截到的处理器ModelAndView:返回的模型视图对象 无返回值
afterCompletion 视图渲染完成后执行(整个流程结束后),可用于资源清理、日志记录或异常处理 Handler:拦截到的处理器Exception:整个流程中出现的异常对象(如果有) 无返回值

# 2、拦截器快速入门

编写MyInterceptor01实现HandlerInterceptor接口:

public class MyInterceptor01 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("Controller 方法执行之前...");
        return true; // 放行,继续执行后续流程
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("Controller 方法执行之后...");
        // 可以对 modelAndView 进行修改,比如添加公共数据
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("渲染视图结束,整个流程完毕...");
        // 可用于资源清理、日志记录、异常处理等
    }
}

配置Interceptor

<!--配置拦截器-->
<mvc:interceptors>
   <mvc:interceptor>
     <!--配置对哪些资源进行拦截操作-->
     <mvc:mapping path="/*"/>
     <bean class="com.itheima.interceptor.MyInterceptor01"></bean>
   </mvc:interceptor>
</mvc:interceptors>

# 3、拦截器执行顺序

拦截器三个方法的执行顺序

当每个拦截器都是放行状态时,三个方法的执行顺序如下:

image-20250729005040006

当Interceptor1和Interceptor2处于放行,Interceptor3处于不放行时,三个方法的执行顺序如下:

image-20250729005055648

拦截器执行顺序取决于 interceptor 的配置顺序

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/target"/>
        <bean class="com.itheima.interceptor.MyInterceptor02"/>
    </mvc:interceptor>

    <mvc:interceptor>
        <mvc:mapping path="/*"/>
        <bean class="com.itheima.interceptor.MyInterceptor01"/>
    </mvc:interceptor>
</mvc:interceptors>

# 4、拦截器执行原理

请求到来时先会使用组件HandlerMapping去匹配Controller的方法(Handler)和符合拦截路径的Interceptor,Handler和多个Interceptor被封装成一个HandlerExecutionChain的对象HandlerExecutionChain 定义如下:

public class HandlerExecutionChain {
    /**
     * 映射的 Controller 的处理器对象(可以是 Controller 实例或者具体方法封装)
     */
    private final Object handler;

    /**
     * 当前 Handler 关联的拦截器集合,按顺序执行
     */
    private final List<HandlerInterceptor> interceptorList;

    // ... 省略其他代码 ...
}

在DispatcherServlet的doDispatch方法中执行拦截器

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {
    // 根据请求信息获得 HandlerExecutionChain,包含处理器和拦截器链
    HandlerExecutionChain mappedHandler = this.getHandler(request);
    
    // 获得对应的处理器适配器(HandlerAdapter),用于调用具体处理器
    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
    
    // 执行所有拦截器的前置方法 preHandle
    // 如果有一个返回 false,则中断后续流程,直接返回
    if (!mappedHandler.applyPreHandle(request, response)) {
        return;
    }
    
    // 执行处理器(通常是 Controller 中的方法),返回模型和视图信息
    ModelAndView mv = ha.handle(request, response, mappedHandler.getHandler());
    
    // 执行所有拦截器的后置方法 postHandle
    mappedHandler.applyPostHandle(request, response, mv);
    
    // 触发所有拦截器的 afterCompletion 方法,处理资源清理和异常等
    this.triggerAfterCompletion(request, response, mappedHandler, null /* 异常参数可传 */);
}

跟踪 HandlerExecutionChain的applyPreHandle方法源码:

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // interceptorIndex 用于记录已经执行过的拦截器索引,方便后续调用 afterCompletion
    for (int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {
        // 取出当前拦截器
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        
        // 调用当前拦截器的 preHandle 方法
        // 如果返回 false,表示拦截请求,后续流程中断
        if (!interceptor.preHandle(request, response, this.handler)) {
            // 立即触发已经执行过的拦截器的 afterCompletion 方法进行资源清理
            this.triggerAfterCompletion(request, response, null);
            return false; // 阻止继续执行后续处理器
        }
    }
    return true; // 所有拦截器都放行,继续执行处理器
}

跟踪 HandlerExecutionChain的applyPostHandle方法源码:

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
    // 逆序遍历拦截器列表,确保后注册的拦截器先执行 postHandle
    for (int i = this.interceptorList.size() - 1; i >= 0; --i) {
        // 取出当前拦截器
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        // 执行拦截器的 postHandle 方法,可对 ModelAndView 进行修改
        interceptor.postHandle(request, response, this.handler, mv);
    }
}

跟踪HandlerExecutionChain的triggerAfterCompletion方法源码:

void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
    // 逆向遍历已执行过的拦截器,从最后一个执行过的拦截器开始
    for (int i = this.interceptorIndex; i >= 0; --i) {
        // 取出当前拦截器
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        try {
            // 执行拦截器的 afterCompletion 方法,处理清理或异常处理逻辑
            interceptor.afterCompletion(request, response, this.handler, ex);
        } catch (Throwable t) {
            // 记录 afterCompletion 方法中的异常,避免影响后续清理工作
            logger.error("HandlerInterceptor.afterCompletion threw exception", t);
        }
    }
}

image-20250729005354784

上次更新: 2025/07/28, 17:18:00
SpringMVC的响应处理
SpringMVC的全注解开发

← SpringMVC的响应处理 SpringMVC的全注解开发→

Theme by Vdoing | Copyright © 2022-2025 Salmon's Blog
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式