一文就够!SpringBoot拦截器及源码分析

SpringBoot(十五)拦截器 阅读详情

1、拦截器是什么

java里的拦截器(Interceptor)是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。在AOP中,拦截器用于在某个方法或者字段被访问之前进行拦截,然后在之前或者之后加入某些操作。

上面的Action一般指的就是我们Controller层的接口。

2、自定义拦截器

一般自定义一个拦截器分为三步

(1)编写一个拦截器实现 HandlerInterceptor 接口。

(2)拦截器注册到容器中。

(3)配置拦截规则。

2.1 编写拦截器

我们新建一个SpringBoot项目,然后自定义一个拦截器 LoginInterceptor ,拦截未登录状态下的某些请求。JDK1.8开始,接口的方法加上 default 关键字可以有默认实现,所以实现一个接口只需要实现没有加该关键字的方法。

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 登录拦截器
 */
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    /**
     * 目标方法执行之前执行
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 获取请求路径
        String requestUrl = request.getRequestURI();
        log.info("请求的路径是: {}", requestUrl);

        String username = request.getParameter("username");
        if (username != null) {
            // 放行
            return true;
        }

        request.setAttribute("msg", "请先登录");
        // 携带msg跳转到登录页
        request.getRequestDispatcher("/").forward(request, response);
        return false;
    }

    /**
     * 目标方法完成以后执行
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle执行");
    }

    /**
     * 页面渲染以后执行
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion执行");
    }
}

2.2 注册和配置拦截器

在SpringBoot中,我们需要自定义配置的时候,只需要实现 WebMvcConfigurer 类重写对应的方法即可。这里我们需要配置拦截器,那么重写它的 addInterceptors 方法即可。

import com.codeliu.interceptor.LoginInterceptor;
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 WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**")  // 拦截所有路径
                .excludePathPatterns("/","/login","/css/**","/fonts/**","/images/**","/js/**");  // 不拦截这些路径
    }
}

注意如果我们配置了拦截所有的路径,那么一定要排除掉静态资源,不然图片样式都会被拦截。

通过上面几步,我们就实现了一个给系统加了一个拦截器。启动验证即可。

3、拦截器原理

我们通过打断点调试的方法,看看从浏览器请求开始到后端是如何进行处理的。在 DispatcherServlet 的 doDispatch 方法打上断点,这是请求的入口,浏览器发送请求后,由此方法进行转发和处理。

debug模式启动应用,访问任意接口,跟踪代码流程

3.1 找到可以处理请求的handler以及handler的所有拦截器

这里找到了 HandlerExecutionChain 以及拦截器链,里面有三个拦截器,我们自定义的 LoginInterceptor 和系统默认的两个拦截器。

3.2 执行拦截器的preHandle方法

在 doDispatch 方法中,有下面两行代码

// 执行拦截器的preHandle方法,如果返回为fasle,则直接return,不执行目标方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    return;
}

// 反射执行目标方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

我们进入 applyPreHandle 方法,看看该方法的逻辑

/**
 * Apply preHandle methods of registered interceptors.
 * @return {@code true} if the execution chain should proceed with the
 * next interceptor or the handler itself. Else, DispatcherServlet assumes
 * that this interceptor has already dealt with the response itself.
 */
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 遍历拦截器
    for (int i = 0; i < this.interceptorList.size(); i++) {
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        // 执行当前拦截器的preHandle方法
        if (!interceptor.preHandle(request, response, this.handler)) {
            // 如果preHandle方法返回为false,则执行当前拦截器的afterCompletion方法
            triggerAfterCompletion(request, response, null);
            return false;
        }
        // 记录当前拦截器的下标
        this.interceptorIndex = i;
    }
    return true;
}

通过上面的代码, 我们知道如果当前拦截器的 preHandle 方法返回为 true ,则会继续执行下一拦截器的 preHandle 方法,否则执行拦截器的 afterCompletion 方法。

那么我们看看 triggerAfterCompletion 方法的逻辑。

/**
 * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
 * Will just invoke afterCompletion for all interceptors whose preHandle invocation
 * has successfully completed and returned true.
 */
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 ex2) {
            logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
        }
    }
}

通过上面的代码,我们知道对于拦截器的 afterCompletion 方法,是反向执行的。

3.3 执行目标方法

如果上面拦截器的所有 preHandle 方法返回都为 true ,那么在 doDispatch 方法内就不会直接return,而是继续往下执行目标方法。如果任何一个拦截器的 preHandle 方法返回为 false ,那么执行完拦截器(已经执行过 preHandle 方法的拦截器)的 afterCompletion 方法后,在 doDispatch 方法内会直接return,不会执行目标方法。

通过下面的代码执行目标方法

// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

内部具体怎么执行的就不看了,看看执行完后的逻辑。

3.4 执行拦截器的postHandle方法

目标方法执行完后,代码往下走

mappedHandler.applyPostHandle(processedRequest, response, mv);

查看 applyPostHandle 的逻辑

/**
 * Apply postHandle methods of registered interceptors.
 */
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
    throws Exception {
	// 反向遍历
    for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        // 执行当前拦截器的postHandle方法
        interceptor.postHandle(request, response, this.handler, mv);
    }
}

倒序执行拦截器的 postHandle 方法

3.5 执行拦截器的afterCompletion方法

继续往下走

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

进入该方法,该方法会处理执行结果,渲染页面,该方法的最后,执行下面的代码

3.6 异常处理

如果在执行 doDispatch 方法过程中,抛出了异常,在catch模块,都会触发执行 afterCompletion 方法

4、总结

上面的过程,大概可以总结为以下几步:

(1)根据当前请求,找到可以处理请求的handler和handler的所有拦截器。

(2)顺序执行所有拦截器的 preHandle 方法

  • 如果当前拦截器的 preHandle 方法返回为 true ,则执行下一拦截器的 preHandle 方法。
  • 如果当前拦截器返回为false,倒序执行所有已经执行了的拦截器的 afterCompletion 。

(3)如果任何一个拦截器返回false,执行返回,不执行目标方法。

(4)所有拦截器都返回true,执行目标方法。

(5)倒序执行所有拦截器的 postHandle 方法。

(6)前面的步骤有任何异常都会触发倒序执行 afterCompletion 方法。

(7)页面成功渲染后,也会倒序执行 afterCompletion 方法。

Spring Boot拦截器 本文介绍了Spring Boot拦截器的作用和原理,并给出了一个简单的示例来演示如何通过拦截器实现请求日志的记录。拦截器是开发中一个非常有用的工具,可以帮助开发人员处理请求、记录日志、鉴权和处理异常。请求日志记录:拦截器可以记录请求的信息,如请求方法、路径、请求参数等。现在,我们的拦截器已经注册到了Spring Boot应用程序中,接下来我们可以在控制器类中使用它。在上面的代码中,我们在preHandle方法中记录了请求的方法和路径,并使用SLF4J日志框架打印到日志中。 阅读详情

相关推荐

SpringBoot拦截器原理解析及使用方法

主要介绍了SpringBoot拦截器原理解析及使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

Springboot——拦截器

假设controller层抛了异常,在这里是可以拿到异常对象的,但是我们有异常处理机制,所以这里就没有那么大的需求了。封装了SpringMVC进行页面跳转的相关数据,但是我们现在都是反JSON,一般不会这么搞了。是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行。通过这个ex可以拿到原始的程序执行过程中出现的异常的。那当我们配置了两个拦截器以后,会有一个执行顺序。Object handler 是什么参数。request:请求对象。response:响应对象。

weixin_51351637的博客 4万+

光线追踪渲染实战:蒙特卡洛路径追踪及其c++实现

光线追踪超越了传统的图形流水线,是一种现代的渲染。光线追踪是一种基于物理的渲染方法,通过模拟光在介质中的真实表现来输出足以逼近现实的图像。光线从光源出发,经过各种反射折射,进入摄像机。通过渲染方程描述一点的颜色,并且通过蒙特卡洛方法求解渲染方程来获取最终的像素颜色。

AKGWSB 's blog 1万+

全面了解SpringBoot拦截器

拦截器(Interceptor)是一种特殊的组件,它可以在请求处理的过程中对请求和响应进行拦截和处理。拦截器可以在请求到达目标处理器之前、处理器处理请求之后以及视图渲染之前执行特定的操作。拦截器的主要目的是在不修改原有代码的情况下,实现对请求和响应的统一处理。本文详细介绍了SpringBoot中的拦截器,包括拦截器的概念、作用、实现方式、执行顺序、生命周期以及高级应用。我们还探讨了拦截器的性能优化策略和常见问题。希望本文能帮助您更好地理解和使用SpringBoot中的拦截器。

万猫学社 2万+

离线语音识别模块LD3320实战:如何低成本给STM32设备加上‘耳朵’和‘嘴巴’?

本文详细介绍了如何为STM32设备集成LD3320离线语音识别模块,实现低成本语音交互方案。从硬件连接到STM32底层驱动实现,再到指令训练与词条优化技巧,完整解析了唤醒词检测与自定义指令识别的全过程。LD3320作为非特定人声识别芯片,无需网络连接,适用于智能家居、工业控制等场景,是嵌入式开发者的理想选择。

weixin_30906185的博客 556

SAP-MM-PR分配货源并转PO

SAP-MM-PR分配货源并转PO

yanzibing99的博客 5476

SpringBoot拦截器及源码分析

1、拦截器是什么 java里的拦截器(Interceptor)是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。在AOP中,拦截器用于在某个方法或者字段被访问之前进行拦截,然后再之前或者之后加入某些操作。 上面的Action一般指的就是我们Controller层的接口。 2、自定义拦截器 一般自定义一个拦截器分为三步 (1)编写一个拦截器实现Handle

秃头哥编程 1634

macOS安装Cplex+yalmip

macOS安装Cplex+yalmip

DS 4250

SpringBoot实现拦截器和源码分析

SpringBoot实现拦截器和源码分析 1、定义拦截器 preHandle方法实在是controller执行之前执行 postHandle方法是在controller执行后执行 afterCompletion方法在模板渲染后执行 示例: /** * 登录检查 * 1、配置好拦截器要拦截哪些请求 * 2、把这些配置放在容器中(之前在servlet的时候,实在xml里写,拦截哪些路径) * 3、 */ @Slf4j public class LoginInterceptor implement

sxp知识共享 819

Skynet 框架面试题

本文整理了游戏服务端开发面试中 Skynet 框架的高频考点,涵盖底层架构、消息派发、协程调度、网络 I/O、harbor 跨机通信、内存管理、socket 处理、阻塞操作、错误处理等核心内容。全面覆盖 Skynet 框架的原理、使用和实战问题,追求深入准确,拒绝八股文。

小赖的博客 383

C++中为什么要引入引用变量?

C++引用机制的设计哲学在于平衡性能与安全性。它解决了指针的三个痛点:语法噪音、空指针风险和语义模糊,同时保持了指针的效率优势。引用必须绑定有效对象且不可重绑定的特性增强了安全性,其值语义语法更直观。尤其在运算符重载和const引用场景中,引用展现了不可替代的优势。本质上,引用是编译器优化的指针实现,体现了C++"零开销抽象"的核心思想——既保持底层性能,又提供高级抽象。这种设计允许开发者根据场景灵活选择指针或引用,反映了C++多范式共存的语言智慧。

教学 & 技术专栏 176

关于springboot的拦截器能力源码分析

首先你得有web环境,这个就不说了,springboot下很简单。

liuwenqiang1314的博客 1086

【Claude】Not logged in 错误:未登录状态的判断与 /login 认证路径 bug报错已解决

login 是首选修复:大多数 "Not logged in" 只需重新执行 /login检查系统时间:时间偏差是 Token 验证失败的常见原因避免密钥库被清理:将 Claude Code 添加到系统清理工具的白名单企业环境用 API Key:如果组织禁用 OAuth,使用 API Key 认证区分凭证类型:理解 Not logged in(无凭证)vs Invalid key(有但无效)

博客 7317

【拦截器Interceptor】springboot拦截器的使用和原理

拦截器就是用来拦截指定的请求,在请求前、请求处理后做一些响应的业务逻辑处理,或者在请求完成之后做一些资源释放。拦截器最常用的使用场景就是认证,在请求开始之前,对当前请求进行权限校验,如果当前请求用户具备操作当前请求的权限,就对当前请求放行,允许执行业务逻辑;否则拦截当前请求,直接返回。拦截器的功能通过网关也都是可以实现的,但是一些单体架构还是需要使用拦截器。要在SpringBoot中实现拦截器,首先需要创建一个类并实现HandlerInterceptor接口。

weixin_44823875的博客 2646

YOLOv11+BiFPN双向特征金字塔:全方位解析多尺度检测性能优化指南

飞书链接:https://ecn6838atsup.feishu.cn/wiki/EhRtwBe1CiqlSEkHGUwc5AP9nQe?购买即可解锁800+YOLO优化文章,并且还有海量深度学习复现项目,价格仅需两杯奶茶的钱,每日更新。函数中添加BiFPN的解析逻辑(找到。链接可用,不要多复制空格了。密码:946m22&8。

FJN110的博客 308

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

SpringBoot Web源码分析(五),拦截器和文件上传

文章目录1.5 拦截器1.5.1 拦截器基本用法1. 声明一个自己的拦截器,实现 HandlerInterceptor 接口。2. 将这个拦截器注册到容器中1.5.1 拦截器源码分析1. 根据当前请求,找到 HandlerExecutionChain2. 顺序执行所有拦截器的preHandler 方法3. 如果任何一个拦截器都返回 false,直接不执行目标方法4. 所有拦截器都返回 true,执行目标方法5. 执行PostHandler方法6. 异常直接触发afterCompletion7. 页面渲染完成

Mr_changxin的博客 1570

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

springboot拦截器 跳过_「原创」007|搭上SpringBoot拦截器源码分析专车

本文转载自【微信公众号:java进阶架构师,ID:java_jiagoushi】经微信公众号授权转载,如需转载与原文作者联系专车介绍该趟专车是开往SpringBoot拦截器源码分析的专车什么是拦截器?拦截器就是用来拦截指定的请求,在请求之前、请求处理后做一些响应的业务逻辑处理,或者在请求完成之后做一些资源释放。拦截器最常用的使用场景就是鉴权,在请求开始之前,对当前请求进行权限校验,如果当前请求用户...

weixin_39797693的博客 144

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

源码分析Spring boot拦截器执行顺序

一、提出问题 项目中存在多个拦截器,那么他们的执行顺序是如何的? 如何设置拦截器执行顺序? 二、前期准备 项目结构: 主要代码如下,有拦截器A、B、C,代码基本与下一致: /** * 拦截器 A * * @author ouyang * @version 1.0 * @date 2020/7/30 15:18 **/ public class AInterceptor implements HandlerInterceptor { private final .

花&败 3329

为什么拦截器把正常请求也拦截了_原创007|搭上SpringBoot拦截器源码分析专车

前言如果这是你第二次看到师长,说明你在觊觎我的美色!点赞+关注再看,养成习惯没别的意思,就是需要你的窥屏^_^专车介绍该趟专车是开往SpringBoot拦截器源码分析的专车什么是拦截器?拦截器就是用来拦截指定的请求,在请求之前、请求处理后做一些响应的业务逻辑处理,或者在请求完成之后做一些资源释放。拦截器最常用的使用场景就是鉴权,在请求开始之前,对当前请求进行权限校验,如果当前请求用户具备操作当前请...

weixin_39809175的博客 271

Springboot配置拦截器

Springboot配置拦截器(登录拦截) 1.编写拦截器实现类,实现接口 HandlerInterceptor,重写里面需要的三个比较常用的方法,实现自己的业务逻辑代码(就是自己拦截器拦截时做什么处理) 注意这里环境为springboot为2.1版本 public class AdminInterceptor implements HandlerInterceptor { /**...

lin_dark的博客 2599

springboot中的拦截器

拦截器可以在进入请求方法前做一些操作,也可以在请求方法后和渲染视图后做一些事情。拦截器的实现只需要实现 HandlerInterceptor 接口,并进行配置即可。preHandler:进入请求方法之前执行;:请求方法执行完成之后执行;:视图渲染后执行。如果不设定拦截器顺序,preHandle 方法执行顺序与拦截器注册时顺序一致,postHandle 和 afterCompletion 方法执行顺序相反;

weixin_44153131的博客 4930

springboot源码分析(五)拦截器源码分析

/** * 登录检查 * 1.配置好拦截器拦截哪些请求 * 2.把这些配置放在容器中 */ @Slf4j public class Logininterceptor implements HandlerInterceptor { /** * 目标方法执行之前 * @param request * @param response * @param handler * @return * @throws Exception *

weixin_42673583的博客 713

SpringBoot源码分析系列之三:拦截器的优雅实现

Java面试核心知识点一共有30个专题,足够读者朋友们应付面试啦,也节省朋友们去到处搜刮资料自己整理的时间!Java面试核心知识点《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!核心知识点一共有30个专题,足够读者朋友们应付面试啦,也节省朋友们去到处搜刮资料自己整理的时间![外链图片转存中…(img-eVkgeD4y-1712206185125)]Java面试核心知识点《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》

2401_84046895的博客 834

Springboot整合Hibernate拦截器EmptyInterceptor

Springboot整合Hibernate拦截器EmptyInterceptor

2017年 5628

oauth2 如何在拦截器最前面添加fileter_【原创】007|搭上SpringBoot拦截器源码分析专车...

专车介绍 该趟专车是开往SpringBoot拦截器源码分析的专车什么是拦截器?拦截器就是用来拦截指定的请求,在请求之前、请求处理后做一些响应的业务逻辑处理,或者在请求完成之后做一些资源释放。拦截器最常用的使用场景就是鉴权,在请求开始之前,对当前请求进行权限校验,如果当前请求用户具备操作当前请求的权限,就对当前请求放行,允许执行业务逻辑;否则拦截当前请求,不执行业务逻辑。专车问题 第一个问...

weixin_39924481的博客 257

SpringBoot源码分析:拦截器注册原理

注册拦截器原理 配置拦截器 在介绍底层添加拦截器之前,首先简单介绍一下如何添加拦截器。我们只需要一个实现HandlerInterceptor接口的类并在MVC配置类中通过重写addInterceptors方法将该类添加到拦截器中。 实现HandlerInterceptor public class LoginHandlerInterceptor implements HandlerInterceptor { //用于拦截 @Override public boolean preHand

bejsoiv的博客 711
上一篇: 这一篇就够了!Kafka面试前的准备,建议收藏
下一篇: 阿里大佬私人珍藏的MySQL笔记,学到就是赚到
程序员职业指南
博客等级 码龄4年 2138粉丝 960原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值