扒一扒@Retryable注解,很优雅,有点意思! (4)

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 扒一扒@Retryable注解,很优雅,有点意思! (4)

Recover逻辑


首先要说明的是 @Recover 注解并不是一个必须要有的东西,前面我们也分析了,就不再赘述。

但是这个功能用起来确实是不错的,绝大部分异常都应该有对应的兜底措施。

这个东西,就是来执行兜底的动作的。

它的源码也非常容易找到,就紧跟在重试逻辑之后:

image.png

下 Debug 几步你就会走到这个地方来:

org.springframework.retry.annotation.RecoverAnnotationRecoveryHandler#recover


image.png

又是一个反射调用,这里的 method 已经是 channelNotResp 方法了。

那么问题就来了:Spring-retry 是怎么知道我的重试方法就是 channelNotResp 的呢?

仔细看上面的截图中的 method 对象,不难发现它是方法的第一行代码产生的:

Method method = findClosestMatch(args, cause.getClass());

这个方法从名字和返回值上看叫做找一个最相近的方法。但是具体不太明白啥意思。

跟进去看一眼它在干啥:

image.png

image.png

这个 Map 里面的 channelNotResp 是什么时候放进去的呢?

很简单,看一下这个 Map 的 put 方法调用的地方就完事了:

image.png

就这两个 put 的地方,源码位于下面这个方法中:

org.springframework.retry.annotation.RecoverAnnotationRecoveryHandler#init

从截图中可以看出,这里是在找 class 里面有没有被 @Recover 注解修饰的方法。

我在第 172 行打上断点,调试一下看一下具体的信息,你就知道这里是在干什么了。

image.png

在你发起调用之后,程序会在断点处停下,至于是怎么走到这里的,前面说过,看调用堆栈,就不再赘述了。

关于这个 doWith 方法,我们把调用堆栈往上看一步,就知道这里是在解析我们的 RetryService 类里面的所有方法:

image.png

当解析到 channelNotResp 方法的时候,会识别出该方法上标注了 @Recover 注解。

但从源码上看,要进行进一步解析,要满足 if 条件。而 if 条件除了要有 Recover 之外,还需要满足这个东西:

method.getReturnType().isAssignableFrom(failingMethod.getReturnType())

isAssignableFrom 方法是判断是否为某个类的父类。

就是的 method 和 failingMethod 分别如下:


image.png

这是在检查被 @Retryable 标注的方法和被 @Recover 标注的方法的返回值是否匹配,只有返回值匹配才说明这是一对,应该进行解析。

比如,我把源码改成这样:

image.png

当它解析到 channelNotRespStr 方法的时候,会发现虽然被 @Recover 注解修饰了,但是返回值并不一致,从而知道它并不是目标方法 callChannel 的兜底方法。

源码里面的常规套路罢了。

再加入一个 callChannelSrt 方法,在上面的源码中 Spring-retry 就能帮你解析出谁和谁是一对:

image.png

接着看一下如果满足条件,匹配上了,if 里面在干啥呢?

image.png

这是在获取方法上的入参呀,但是仔细一看,也只是为了获取第一个参数,且这个参数要满足一个条件:

Throwable.class.isAssignableFrom(parameterTypes[0])

必须是 Throwable 的子类,也就说说它必须是一个异常。用 type 字段来承接,然后下面会把它给存起来。

第一次看的时候肯定没看懂这是在干啥,没关系,我看了几次看明白了,给你分享一下,这里是为了这一小节最开始出现的这个方法服务的:

image.png

在这里面获取了这个 type,判断如果 type 为 null 则默认为 Throwable.class。

如果有值,就判断这里的 type 是不是当前程序抛出的这个 cause 的同类或者父类。

再强调一遍,从这个方法从名字和返回值上看,我们知道是要找一个最相近的方法,前面我说具体不太明白啥意思都是为了给你铺垫了一大堆 methods 这个 Map 是怎么来的。

其实我心里明镜儿似的,早就想扯下它的面纱了。

image.png

来,跟着我的思路马上就能看到葫芦里到底卖的是什么酒了。

你想,findClosestMatch,这个 Closest 是 Close 的最高级,表示最接近的意思。

既然有最接近,那么肯定是有几个东西放在一起,这里面只有一个是最符合要求的。

在源码中,这个要求就是“cause”,就是当前抛出的异常。

而“几个东西”指的就是这个 methods 装的东西里面的 type 属性。

还是有点晕,对不对,别慌,下面这张图片一出来,马上就不晕了:

image.png

目录
相关文章
|
6月前
|
Java 编译器
你说啥什么?注解你还不会?
你说啥什么?注解你还不会?
70 0
|
Java 编译器 数据库连接
注解
注解是JAVA5引入JAVA的一个特性,理解起来会有点抽象,这里笔者先给出自己对注解的一个理解——注解就是一张便签! 其次要有一个概念就是注解的应用是基于反射的。 本文举出的三个实例中例1和例3是引用其它的优秀文献 出处为how2J以及 https://blog.csdn.net/briblue/article/details/73824058一文
70 0
|
Java 测试技术 Spring
关于@RunWith注解的一点问题
IDEA写springboot测试关于@Runwith的小问题
237 0
关于@RunWith注解的一点问题
|
Java 编译器
关于@FunctionalInterface注解
FunctionalInterface
458 0
关于@FunctionalInterface注解
|
Java 编译器 Spring
什么是注解
什么是注解
|
存储 JSON Java
一文学会注解的正确使用姿势
一文学会注解的正确使用姿势
一文学会注解的正确使用姿势
|
XML Dubbo Java
duboo注解使用详解
当越来越的的接口与实现类的增加后,duboo的xml配置会越来越多,为了防止几百几千行的代码,减少开发人员配置xml的工作量,使用duboo的注解模式,减少配置多出问题多的可能性!
170 0
duboo注解使用详解
|
Java 程序员 开发工具
扒一扒@Retryable注解,很优雅,有点意思! (1)
扒一扒@Retryable注解,很优雅,有点意思! (1)
373 0
扒一扒@Retryable注解,很优雅,有点意思! (1)
|
缓存
扒一扒@Retryable注解,很优雅,有点意思! (2)
扒一扒@Retryable注解,很优雅,有点意思! (2)
314 0
扒一扒@Retryable注解,很优雅,有点意思! (2)