springmvc 全局异常处理器配置的三种方式深入底层源码分析原理
文章目录
- springmvc 全局异常处理器配置的三种方式&深入底层源码分析原理
- 配置全局异常处理器的三种方式
- 实现接口HandlerExceptionResolver并配置到WebMvcConfigurer
- 注解式配置@ExceptionHandler
- controller里方法上定义@ExceptionHandler
- 深入源码分析
- 进入DispatcherServlet
- 执行handler方法并catch异常
springmvc 全局异常处理器配置的三种方式&深入底层源码分析原理
配置全局异常处理器的三种方式
实现接口HandlerExceptionResolver并配置到WebMvcConfigurer
定义一个类实现这个接口
/*** Interface to be implemented by objects that can resolve exceptions thrown during* handler mapping or execution, in the typical case to error views. Implementors are* typically registered as beans in the application context.** <p>Error views are analogous to JSP error pages but can be used with any kind of* exception including any checked exception, with potentially fine-grained mappings for* specific handlers.** @author Juergen Hoeller* @since 22.11.2003*/
public interface HandlerExceptionResolver {/*** Try to resolve the given exception that got thrown during handler execution,* returning a {@link ModelAndView} that represents a specific error page if appropriate.* <p>The returned {@code ModelAndView} may be {@linkplain ModelAndView#isEmpty() empty}* to indicate that the exception has been resolved successfully but that no view* should be rendered, for instance by setting a status code.* @param request current HTTP request* @param response current HTTP response* @param handler the executed handler, or {@code null} if none chosen at the* time of the exception (for example, if multipart resolution failed)* @param ex the exception that got thrown during handler execution* @return a corresponding {@code ModelAndView} to forward to,* or {@code null} for default processing in the resolution chain*/@NullableModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);}
定义一个配置类实现接口 WebMvcConfigurer 并重写方法configureHandlerExceptionResolvers将你定义的这个resolver加入到resolvers这个List即可
注解式配置@ExceptionHandler
要让spring扫描到这个类,一种方式是直接把这个类放到springboot能扫描的目录下(启动类当前目录或者子目录,或者在启动类手动配置的扫描组件目录),另一种方式是放在工具类里,定义到spring.factories里让spring扫描到,注意设置个@Order(0)让这个优先于springmvc注解错误处理器之前注入到容器,否则会无效,因为那个处理器只加载一次,后续不会再扫容器里的实例了。
/*** @author humorchen* date: 2024/6/11* description: 认证全局异常配置**/@Slf4j
@RestControllerAdvice
@Order(0)
public class AuthExceptionResolver {public static final int TOKEN_ERROR_CODE = HttpStatus.HTTP_UNAUTHORIZED;public static final String ERROR_MSG = "未登录或登录已失效!";/*** TOKEN相关异常** @param e* @return*/@ExceptionHandler({SaTokenException.class, JWTVerificationException.class})public Result<String> resolveAuthTokenException(Exception e) {log.info("handleSaTokenException {}: {}", e.getClass().getName(), e.getMessage());return Result.fail(TOKEN_ERROR_CODE, ERROR_MSG);}}
看到上面代码,你会有一个疑问,要是定义了多个,它怎么确定该用哪个呢,源码中使用ExceptionDepthComparator排序,排序规则是按照继承顺序来(继承关系越靠近数值越小,当前类最小为0,顶级父类Throwable为int最大值),排序之后选取继承关系最靠近的那个,并且ExceptionHandlerMethodResolver的exceptionLookupCache中,key为当前抛出的异常,value为解析出来的匹配method.
org.springframework.core.ExceptionDepthComparator

controller里方法上定义@ExceptionHandler
@RestController
public class ExceptionController {@ExceptionHandler(Exception.class)public ResponseEntity<String> handleException(Exception ex) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An error occurred: " + ex.getMessage());}@RequestMapping("/test")public String test() throws Exception {throw new Exception("Test exception!");}
}
深入源码分析
进入DispatcherServlet

执行handler方法并catch异常

调用processDispatchResult处理分发处理结果

发现有异常则调用processHandlerException 处理handler异常

如果有handlerExceptionResovlers就循环调用,直到有一个resolver返回了非空值就跳出循环

默认resolver,就是把这个异常放到了request.attribute里头去了


HandlerExceptionResolverComposite,是handler异常处理器的复合类,把这些resolver放到它内部一个集合


点开这个类源码看下,其实就是在我们在webmvcconfigurer里配置这个方法的时候,把配置的所有resolver设置进这个类里的this.resolvers 集合去了,进调试可以看到有两个resolver,一个是我自定义并配置上的ExceptionResolver,另一个是个Http请求异常处理器(seata的HttpHandlerExceptionResolver)


分布式事务用来清理ID的,不用管

第三个也是我注入的那个错误处理器
如果经过这些处理器,有一个返回了非空的结果,这个异常 处理就会被结束

执行完所有的resolver,有一个返回了ModelAndView的话就返回这个ModelAndView,否则继续抛出异常往上层传递。然后触发请求handler的triggerAfterCompletion,也就是执行你所有跟这个handler绑定的HandlerInterceptor的afterCompletion

前面看的都是HandlerExceptionResolver的实现,还有那个注解式的实现,我们也一起看下这个ExceptionHandlerExceptionResolver 类的源码,就是用来处理 @ExceptionHandler的
/*** An {@link AbstractHandlerMethodExceptionResolver} that resolves exceptions* through {@code @ExceptionHandler} methods.** <p>Support for custom argument and return value types can be added via* {@link #setCustomArgumentResolvers} and {@link #setCustomReturnValueHandlers}.* Or alternatively to re-configure all argument and return value types use* {@link #setArgumentResolvers} and {@link #setReturnValueHandlers(List)}.** @author Rossen Stoyanchev* @author Juergen Hoeller* @since 3.1*/
public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolverimplements ApplicationContextAware, InitializingBean {@Nullableprivate List<HandlerMethodArgumentResolver> customArgumentResolvers;@Nullableprivate HandlerMethodArgumentResolverComposite argumentResolvers;@Nullableprivate List<HandlerMethodReturnValueHandler> customReturnValueHandlers;@Nullableprivate HandlerMethodReturnValueHandlerComposite returnValueHandlers;private List<HttpMessageConverter<?>> messageConverters;private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();private final List<Object> responseBodyAdvice = new ArrayList<>();@Nullableprivate ApplicationContext applicationContext;private final Map<Class<?>, ExceptionHandlerMethodResolver> exceptionHandlerCache =new ConcurrentHashMap<>(64);private final Map<ControllerAdviceBean, ExceptionHandlerMethodResolver> exceptionHandlerAdviceCache =new LinkedHashMap<>();
在这个bean执行到afterPropertiesSet这个时间点的时候进行了 @ExceptionHandler实现的扫描initExceptionHandlerAdviceCache(),如果你的 @ExceptionHandler配置bean在这个时间点之后注入进IOC容器的话,那么恭喜你,你的配置不会生效,因此前面我说要让自己的这个配置优先级变高,才能生效。

ControllerAdviceBean.findAnnotatedBeans(getApplicationContext())
把所有的标注了@ControllerAdvice注解的bean全部找出来并根据order排序返回了


看到这你会疑问还有个@RestControllerAdvice,来看源码,@RestControllerAdvice上标注了@ControllerAdvice

前面已经看了加载过程,现在看执行处理异常的代码,其实就是拿着加载好的处理器,去调用处理,然后参数呢又是可选的,随便你定义,那个其实是反射拿到你方法定义的参数,然后跟现有能给你的一些参数比对类型,然后组成一个参数数组,传入执行对象、参数反射执行方法,然后就拿到了异常处理结果

组装生成调用参数数组的方法就在这org.springframework.web.method.support.InvocableHandlerMethod#getMethodArgumentValues

也就是把异常对象和当前的handlerMethod给你了,你自己可以写到参数里它会注入给你的


ExceptionHandler原理另一个作者也写的不错:
从源码角度去深入分析关于Spring的异常处理ExceptionHandler的实现原理
相关文章:
springmvc 全局异常处理器配置的三种方式深入底层源码分析原理
文章目录 springmvc 全局异常处理器配置的三种方式&深入底层源码分析原理配置全局异常处理器的三种方式实现接口HandlerExceptionResolver并配置到WebMvcConfigurer注解式配置ExceptionHandlercontroller里方法上定义ExceptionHandler 深入源码分析进入DispatcherServlet执…...
MySQL 8.0 安装、配置、启动、登录、连接、卸载教程
目录 前言1. 安装 MySQL 8.01.1 下载 MySQL 8.01.2 安装 MySQL 8.0 2. 配置 MySQL 8.02.1打开环境变量2.2新建变量 MYSQL_HOME2.3编辑 Path 变量 3. 启动MySQL 8.03.1验证安装与配置是否成功3.2初始化并注册MYSQL3.3 启动MYSQL服务 4.登录MySQL4.1修改账户默认密码4.2登录MYSQL…...
Pythone 程序打包成 exe
1.安装pyinstaller # 安装 pip install pyinstaller # 查看版本 pyinstaller -v2.更新pyinstaller 版本 # 更新 pip install --upgrade pyinstaller # 查看版本 pyinstaller -v3.切换到 py文件所在目录 #切换到.py所在的目录 E: cd cd E:\x-svn_x-local\04PythoneProjects\A…...
“卫星-无人机-地面”遥感数据快速使用及地物含量计算
随着我国高分系列、欧比特系列、自然资源卫星系列等卫星数据的获取,以及美国Headwall、芬兰SPECIM、挪威HySpex、我国双利合谱、智科远达、中科谱光等无人机数据的兴起,遥感数据越来越易得。这些多源数据,在与典型地面点结合后,将…...
设计模式学习(二)工厂模式——简单工厂模式
设计模式学习(二)工厂模式——简单工厂模式 前言简单工厂模式简介示例优点缺点使用场景 前言 工厂模式是一种常用的设计模式,属于创建型模式之一。它的主要目的是为了解耦组件之间的依赖关系。通过使用工厂模式,系统中的具体类的…...
贷款业务——LPR、APR、IRR
文章目录 LPR(Loan Prime Rate)贷款市场报价利率APR(Annual Percentage Rate)年化百分比利率IRR(Internal Rate of Return)内部收益率 LPR、APR 和 IRR 是三个不同的金融术语,LPR 是一种市场利率…...
Simscape Multibody与RigidBodyTree:机器人建模
RigidBodyTree:主要用于表示机器人刚体结构的动力学模型,重点关注机器人的几何结构、质量和力矩,以及它们如何随时间变化。它通常用于计算机器人的运动和受力情况。Simscape Multibody:作为Simscape的一个子模块,专门用…...
数据结构刷题-链表
数据结构刷题-链表 总结:1 链表的解法总结: 1 链表的知识点:1 LC链表合集:1.1 lc206反转链表: 双指针:lc25: K个一组翻转链表:栈1.2 lc203移除链表元素:1.3 设计链表:1.4…...
Java应届第一年规划
👽System.out.println(“👋🏼嗨,大家好,我是代码不会敲的小符,目前工作于上海某电商服务公司…”); 📚System.out.println(“🎈如果文章中有错误的地方,恳请大家指正&…...
js之简单轮播图
今天给大家封装一个简单的轮播图,可以点击下一张上一张以及自动轮播 <!DOCTYPE html> <html><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>走马…...
GitLab教程(二):快手上手Git
文章目录 1.将远端代码克隆到本地2.修改本地代码并提交到远程仓库3.Git命令总结git clonegit statusgit addgit commitgit pushgit log 首先,我在Gitlab上创建了一个远程仓库,用于演示使用Gitlab进行版本管理的完整流程: 1.将远端代码克隆到本…...
前端渲染大量数据思路【虚拟列表】【异步机制】
当浏览器遇到性能瓶颈导致页面卡顿时,你会怎么处理?如何查找问题的原因? 浏览器本身自带性能检测工具,通常我们分析由脚本导致的页面卡顿会选择 性能(performance) 选项卡,在其中我们可以找到导…...
Ubuntu24.04记录网易邮箱大师的安装
邮箱大师下载 官网自行下载,下载后文件名“mail.deb" https://dashi.163.com/ 安装发现缺少依赖 #mermaid-svg-8wqpqFSBVOPD7NGP {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-8wqpqFSBVOPD7NGP …...
PDF编辑与转换的终极工具智能PDF处理Acrobat Pro DC
Acrobat Pro DC 2023是一款功能全面的PDF编辑管理软件,支持创建、编辑、转换、签署和共享PDF文件。它具备OCR技术,可将扫描文档转换为可编辑文本,同时提供智能PDF处理技术,确保文件完整性和可读性。此外,软件还支持电子…...
Django UpdateView视图
UpdateView是Django中的一个通用视图,用于处理对象的更新操作。它允许用户更新一个已经存在的对象。UpdateView通常与一个模型表单一起使用,这样用户就可以看到当前对象的值,并可以修改它们。 1,添加视图 Test/app3/views.py fr…...
【CS.SE】2024年,你应该选择计算机专业吗?详细分析与未来展望
文章目录 1. 引言1.1 背景介绍 2. 计算机相关专业的现状与挑战2. 计算机相关专业的现状与挑战2.1 行业内的就业趋势2.1.1 现有就业数据2.1.2 行业需求变化 2.2 市场饱和度与竞争2.2.1 毕业生数量增长2.2.2 薪资与职业发展 2.3 技术创新与行业发展2.3.1 新兴技术的发展2.3.2 全球…...
后端开发面经系列 -- 华为OD -- C++面经(全)
华为OD – C面经(全) 公众号:阿Q技术站 文章目录 华为OD -- C面经(全)一面1、C结构体和类的区别,类默认的访问权限,结构体可以定义成员函数吗?2、多态的意义?多态的意义…...
3072. 将元素分配到两个数组中 II Rust 线段树 + 离散化
题目 给你一个下标从 1 开始、长度为 n 的整数数组 nums 。 现定义函数 greaterCount ,使得 greaterCount(arr, val) 返回数组 arr 中 严格大于 val 的元素数量。 你需要使用 n 次操作,将 nums 的所有元素分配到两个数组 arr1 和 arr2 中。在第一次操…...
day35|1005.K次取反后最大化的数组和 134. 加油站135. 分发糖果
文章目录 python语法记录 sort格式 1005.K次取反后最大化的数组和思路方法一方法二 按照绝对值排序 教程🎈✨ 背住 按照绝对值进行降序排序的语法是: 134. 加油站思路方法一 教程解法方法二 暴力求解 135. 分发糖果思路方法一 总结 python语法记录 sort …...
HWA和BSS区别
芯片中的HWA(Hardware Accelerator)模块功能主要是为了加速雷达信号处理的特定任务。HWA模块在雷达系统中起到关键作用,以下是其主要功能和作用: 信号预处理: 滤波:对接收到的雷达信号进行滤波,…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
