当前位置:网站首页>统一异常处理导致ResponseBodyAdvice失效
统一异常处理导致ResponseBodyAdvice失效
2022-07-30 08:16:00 【AE86Jag】
背景
微服务架构下准备将一些基础功能抽出到公共Jar包中,包括统一异常处理、JwtToken校验、统一请求响应处理等,抽完以后发现,当出现异常时,走了统一异常捕获的逻辑,但是项目中的所有自定义的ResponseBodyAdvice都没有执行,决定一步步DEBUG定位下原因,项目是Springboot 2.3.7.RELEASE版本。
定位过程
首先测试正常的接口,发现ResponseBodyAdvice都是生效的,而且按照设置的顺序执行了,说明这些ResponseBodyAdvice都注册到容器了。
接着猜测是不是ResponseBodyAdvice都执行过只是没有执行beforeBodyWrite方法,在执行supports方法的时候就已经返回,于是在supports方法里面打上断点,看抛异常时是否会走到supports方法,最后发现都没有走supports方法,猜测可能是因为什么规则,把ResponseBodyAdvice都过滤了。
继续DEBUG,看正常流程下ResponseBodyAdvice是如何生效的,因为之前在supports方法都打了断点,直接请求接口,看supports方法之前的调用调用堆栈,如图
主要是前面几个类,栈顶是我自定义的ResponseBodyAdvice,断点打在supports方法上,下面是RequestResponseBodyAdviceChain的processBody方法140行,然后是RequestResponseBodyAdviceChain的beforeBodyWrite方法116行,AbstractMessageConverterMethodProcessor类的writeWithMessageConverters268行,分别在这几个方法上打断点:
下面会走RequestResponseBodyAdviceChain的beforeBodyWrite方法,继续进去看下
for循环里面就是实际去调用每个advice去处理返回结果,要过滤就只能在getMatchingAdvice方法里面了,继续DEBUG
getAdvice()就是获取系统中所有的Advice,因为自定义的ResponseBodyAdvice都是有@ControllerAdvice注解修饰的,所以都是ControllerAdviceBean类型,走的157行的逻辑。parameter参数就是最终返回数据的方法参数,我这里就是统一异常处理的方法。继续进入
可以看到这个方法调用了beanTypePredicate的test方法,beanTypePredicate里面有三个属性,其中有一个是basePackages,在自定义的ResponseBodyAdvice中@RestControllerAdvice指定了包名,其他两个assignableTypes、annotations也是该注解的属性。继续看test方法的内容
到这就能大概知道原因了,就是包名不匹配,ResponseBodyAdvice只能处理指定包名下的返回值处理。其他两个属性可以实现指定注解或者Class类实现ResponseBodyAdvice的功能:
- annotations属性,如果返回的方法不在basePackages包内,直接在方法上指定这个注解
- assignableTypes属性,如果不在basePackages包内,也没有annotations注解,指定Class类也可以
原因
统一异常处理类所在的包名不在@RestControllerAdvice注解的basePackages属性指定的包名下,所以自定义的ResponseBodyAdvice是处理不了统一异常处理返回的数据的
解决方法
- 修改包名,basePackages的包名包含统一异常处理的类
- 增加自定义注解,修饰在异常处理的方法上,并把这个注解写在@RestControllerAdvice注解的annotations属性上
- 将异常处理的类Class对象写在@RestControllerAdvice注解的assignableTypes属性上
总结
框架异常多看源码,多调试,有很大收获。
边栏推荐
猜你喜欢
OA Project Pending Meeting & History Meeting & All Meetings
How to use Jmeter to carry out high concurrency in scenarios such as panic buying and seckill?
电源完整性的去耦和层间耦合电容
回板后,处理器不启动,怎么办?
SQL window function
SwiftUI SQLite 教程之 构建App本地数据库实现创建、读取、更新和删除(教程含完成项目源码)
桌面软件开发框架大赏
Taosi TDengine 2.6+ optimization parameters
用示波器揭示以太网传输机制
开关电源波纹的产生、测量及抑制,一篇全搞定!
随机推荐
2022杭电多校第一场
test4
ant-design form form verification upload component (with personal packaged upload component)
香港服务器iis配置web服务器如何操作?
[Yugong Series] July 2022 Go Teaching Course 021-Slicing Operation of Go Containers
stugc_paper
hcip 第14天学习笔记
七大排序之直接选择排序
JS中如何阻止事件冒泡和默认行为
SQL window function
SwiftUI SQLite 教程之 构建App本地数据库实现创建、读取、更新和删除(教程含完成项目源码)
【Flask框架②】——第一个Flask项目
基于SSM开发实现校园疫情防控管理系统
Apache DolphinScheduler新一代分布式工作流任务调度平台实战-上
Why does typescript2-typescript add type support to js
深入浅出零钱兑换问题——背包问题的套壳
HashSet and LinkedHashSet
C language classic practice questions (3) - "Hanoi Tower (Hanoi)"
如何避免CMDB沦为数据孤岛?
test4