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的实现原理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/350507.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

axios打通fastapi和vue,实现前后端分类项目开发

axios axios是一个前后端交互的工具&#xff0c;负责在前端代码&#xff0c;调用后端接口&#xff0c;将后端的数据请求到本地以后进行解析&#xff0c;然后传递给前端进行处理。 比如&#xff0c;我们用fastapi写了一个接口&#xff0c;这个接口返回了一条信息&#xff1a; …

环保评A的意义与价值

环保评A&#xff0c;这个看似简单的称谓&#xff0c;背后却蕴藏着深厚的环保理念和实践标准。在当今社会&#xff0c;环保已经成为一项全球性的议题&#xff0c;各国都在努力推动绿色发展&#xff0c;实现可持续发展目标。那么&#xff0c;环保评A究竟是全国性的认证还是地方性…

亿达中国武汉园区入选“武汉市科技金融工作站”及“武汉市线下首贷服务站”

近日&#xff0c;武汉市2024科技金融早春行活动在深交所湖北资本市场培育基地举行。会上&#xff0c;第四批武汉市科技金融工作站试点单位名单及第五批武汉地区金融系统线下首贷服务站名单正式公布&#xff0c;武汉软件新城成功入选上述两个名单。 为缓解科技型企业融资难题&a…

profile-3d-contrib,github三维立体图的使用

图片展示: 提示: 这个profile-3d-contrib存储库有时候会出现问题,导致又有使用这个存储库svg的用户显示出现问题. 参考: https://zhuanlan.zhihu.com/p/681786778 原仓库链接&#xff1a; GitHub - yoshi389111/github-profile-3d-contrib: This GitHub Action creates a Gi…

解决javadoc一直找不到路径的问题

解决javadoc一直找不到路径的问题 出现以上问题就是我们在下载jdk的时候一些运行程序安装在C:\Program Files\Common Files\Oracle\Java\javapath下&#xff1a; 一开始是没有javadoc.exe文件的&#xff0c;我们只需要从jdk的bin目录下找到复制到这个里面&#xff0c;就可以使用…

微信公众号打通与登录的实现

今天实现一下与微信公众号进行对接&#xff0c;通过扫描二维码的方式来进行注册与登录&#xff0c;获取用户的微信唯一标识作为用户的username&#xff0c;下面我们开始编写。 骨架建立&#xff1a; 建包&#xff1a; 第一步还是先将骨架建好&#xff0c;与网关骨架差不多&a…

MEMS:Lecture 16 Gyros

陀螺仪原理 A classic spinning gyroscope measures the rotation rate by utilizing the conservation of angular momentum. 经典旋转陀螺仪通过利用角动量守恒来测量旋转速率。 Coriolis Effect and Coriolis Force 科里奥利效应是一种出现在旋转参考系中的现象。它描述了…

外链建设如何进行?

理解dofollow和nofollow链接&#xff0c;所谓dofollow链接&#xff0c;就是可以传递权重到你的网站的链接&#xff0c;这种链接对你的网站排名非常有帮助&#xff0c;这种链接可以推动你的网站在搜索结果中的位置向上爬&#xff0c;但一个网站全是这种有用的链接&#xff0c;反…

人工智能GPU互联技术分析,芯片巨头UALink向英伟达NVLink开战

芯片巨头组团&#xff0c;向英伟达NVLink开战 八大科技巨头——AMD、博通、思科、Google、惠普企业、英特尔、Meta及微软——联合推出UALink&#xff08;Ultra Accelerator Link&#xff09;技术&#xff0c;为人工智能数据中心网络设定全新互联标准。此举旨在打破Nvidia的市场…

本地GPT-window平台 搭建ChatGLM3-6B

一 ChatGLM-6B 介绍 ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型&#xff0c;新一代开源模型 ChatGLM3-6B 已发布&#xff0c;拥有10B以下最强的基础模型&#xff0c;支持工具调用&#xff08;Function Call&#xff09;、代码执行&#xff08;Code Interpreter&…

面试题 17.06. 2出现的次数

题解&#xff1a;. - 力扣&#xff08;LeetCode&#xff09;. - 力扣&#xff08;LeetCode&#xff09; 数位 DP 通用模板_哔哩哔哩_bilibili class Solution { public:int numberOf2sInRange(int n) {std::string str to_string(n);int len str.size();std::vector<std:…

构建旧物回收系统的决策支持系统

内容概要&#xff1a; 在旧物回收系统中&#xff0c;构建一个有效的决策支持系统对于提高管理效率、优化资源配置具有重要意义。本文将探讨如何构建旧物回收系统的决策支持系统&#xff0c;并分析其如何辅助管理者做出更科学的决策。 一、决策支持系统的定义与功能 决策支持…

Ubuntu 18.04下普通用户的一次提权过程

Ubuntu 18.04下普通用户的一次提权过程 一.背景介绍:二.主要调试过程:三.相关命令:1.设置BMC密码,获取BMC IP2.找一台ubuntu搭建TFTP服务,用来替换grub.cfg文件3.从调试服务器的/boot/grub/grub.cfg中提取出recovery mode的配置,简化并生成新的配置文件grub.cfg,放在tftp服务的…

【ARMv8/ARMv9 硬件加速系列 3 -- SVE 指令语法及编译参数详细介绍】

文章目录 SVE 汇编语法SVE 单通道谓词SVE 测试代码 SVE 软件和库支持SVE 编译参数配置-marcharmv8-alseprofilememtagsve2-aessve2-bitpermcryptosve2sve2-sha3sve2-sm4 SVE 汇编语法 在介绍 SVE 汇编指令语法之前&#xff0c;先介绍下如何判断自己所使用的芯片是否实现了SVE功…

第二十三节:带你梳理Vue2:Vue插槽的认识和基本使用

前言: 通过上一节的学习,我们知道了如何将数据从父组件中传递到子组件中, 除了除了将数据作为props传入到组件中,Vue还允许传入HTML, Vue 实现了一套内容分发的 API&#xff0c;这套 API 的设计灵感源自 Web Components 规范草案&#xff0c;将 <slot> 元素作为承载分发…

python 装饰器

装饰器 装饰本质上就是一个闭包函数&#xff0c;它可以对我们已有函数进行额外的功能拓展&#xff0c;装饰器符合了 开发中的封闭开放原则 装饰器的作用 在不改变原有函数的源代码的情况下&#xff0c;给函数增加新的功能 def decorator(fn): # fn: 需要装饰的函数…

2779. 数组的最大美丽值

简单翻译一下题目意思&#xff1a; 对于每个 nums[i] 都可以被替换成 [nums[i]-k, nums[i]k] 区间中的任何数&#xff0c;区间左右是闭的。在每个数字可以替换的前提下&#xff0c;返回数组中最多的重复数字的数量。 第一想法是用一个哈希表&#xff0c;Key 是可以被替换的数…

实现AI口语练习的技术库

国内实现AI口语练习的第三方技术库比较多&#xff0c;以下是一些国内实现AI口语练习的第三方技术库。开发人员可以根据自己的需求选择合适的技术库进行开发。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 讯飞开放平台&#xff1a; …

python如何对list求和

如何在Python中对多个list的对应元素求和&#xff0c;前提是每个list的长度一样。比如&#xff1a;a[1&#xff0c;2&#xff0c;3]&#xff0c;b[2&#xff0c;3&#xff0c;4]&#xff0c;c[3&#xff0c;4&#xff0c;5]&#xff0c;对a&#xff0c;b&#xff0c;c的对应元素…

14.基于人类反馈的强化学习(RLHF)技术详解

基于人类反馈的强化学习&#xff08;RLHF&#xff09;技术详解 RLHF 技术拆解 RLHF 是一项涉及多个模型和不同训练阶段的复杂概念&#xff0c;我们按三个步骤分解&#xff1a; 预训练一个语言模型 (LM) &#xff1b;训练一个奖励模型 (Reward Model&#xff0c;RM) &#xf…