看点:Java 远程调用失败?如何优雅的进行重试? - 综合 -

当前位置:首页  >  综合  > 正文

看点:Java 远程调用失败?如何优雅的进行重试?

看点:Java 远程调用失败?如何优雅的进行重试?
2023-05-06 13:20:21 来源:清一色财经

今天给大家介绍了一下 Spring 的 @Retryable 注解使用,并通过几个 demo 来带大家编写了自己重试拦截器以及回滚方法的时候,是不是感觉用起来会很爽,那还在等什么赶紧用起来吧,其中还有很多细节,只有自己真正的使用过才能体会到。


(相关资料图)

在日常开发的过程中我们经常会需要调用第三方组件或者数据库,有的时候可能会因为网络抖动或者下游服务抖动,导致我们某次查询失败。

这种时候我们往往就会进行重试,当重试几次后依旧还是失败的话才会向上抛出异常进行失败。接下来阿粉就给大家演示一下通常是如何做的,以及如何更优雅的进行重试。

常规做法

我们先来看一下常规做法,常规做法首先会设置一个重试次数,然后通过while循环的方式进行遍历,当循环次数没有达到重试次数的时候,直到有正确结果后就返回,如果重试依旧失败则会进行睡眠一段时间,再次重试,直到正常返回或者达到重试次数返回。

package com.example.demo.service;import org.springframework.retry.annotation.Backoff;import org.springframework.retry.annotation.Retryable;import org.springframework.stereotype.Service;import java.util.Random;import java.util.concurrent.TimeUnit;@Servicepublic class HelloService {  public String sayHello(String name) {    String result = "";    int retryTime = 3;    while (retryTime > 0) {      try {        //        result = name + doSomething();        return result;      } catch (Exception e) {        System.out.println("send message failed. try again in 1"s");        retryTime--;        try {          TimeUnit.SECONDS.sleep(1);        } catch (InterruptedException ex) {          throw new RuntimeException(ex);        }      }    }    return result;  }  private int doSomething() {    Random random = new Random();    int i = random.nextInt(3);    System.out.println("i is " + i);    return 10 / i;  }}

这里为了模拟异常的情况,阿粉在doSomething​函数里面进行了随机数的生成和使用,当随机出来的值为 0 的时候,则会触发java.lang.ArithmeticException异常,因为 0 不能作除数。

接下来我们再对外提供一个接口用于访问,代码如下

package com.example.demo.controller;import com.example.demo.service.HelloService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;@RestControllerpublic class HelloController {  @Autowired  private HelloService helloService;  @GetMapping(value = "/hello")  public String hello(@RequestParam("name") String name) {    return helloService.sayHello(name);  }}

正常启动过后,我们通过浏览器进行访问。

可以看到,我们第一次方法的时候就成功的达到了我们要的效果,随机数就是 0 ,在 1 秒后重试后结果正常。在多试了几次过后,会遇到三次都是 0 的情况,这个时候才会抛出异常,说明服务是真的有问题了。

上面的代码可以看到是有效果了,虽然不是很好看,特别是在还有一些其他逻辑的情况,看上去会很臃肿,但是确实是可以正常使用的,那么有的小伙伴就要问了,有没有一种优雅的方式呢?总不能在很多地方都重复的这样写重试的代码吧。

注解重试

要知道我们普通人在日常开发的时候,如果遇到一个问题肯定是别人都遇到过的,什么时候当我们遇到的问题,没有人遇到过的时候,那说明我们是很前卫的。

因此小伙伴能想到的是不是有简单的方式来进行重试,有的人已经帮我们想好了,可以通过@Retryable注解来实现一样的效果,接下来阿粉就给大家演示一下如何使用这个注解。

首先我们需要在启动类上面加入@EnableRetry​注解,表示要开启重试的功能,这个很好理解,就像我们要开启定时功能需要添加@EnableScheduling​注解一样,Spring​的@Enablexxx注解也是很有意思的,后面我们再聊。

添加完注解以后,需要加入切面的依赖,如下

  org.aspectj  aspectjweaver  1.9.2

如下不加入这个切面依赖,启动的时候会有如下异常

添加的注解和依赖过后,我们需要改造HelloService​里面的sayHello()​方法,简化成如下,增加 @Retryable注解,以及设置相应的参数值。

@Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 1000, multiplier = 2))  public String sayHello(String name){    return name + doSomething();  }

再次通过浏览器访问 http://127.0.0.1:8080/hello?name=ziyou 我们看到效果如下,跟我们自己写的重试一样。

@Retryable 详解

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by FernFlower decompiler)//package org.springframework.retry.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Retryable {    String recover() default "";    String interceptor() default "";    Class[] value() default {};    Class[] include() default {};    Class[] exclude() default {};    String label() default "";    boolean stateful() default false;    int maxAttempts() default 3;    String maxAttemptsExpression() default "";    Backoff backoff() default @Backoff;    String exceptionExpression() default "";    String[] listeners() default {};}

点到这个注解里面,我们可以看到这个注解的代码如下,其中有几个参数我们来解释一下

recover: 当前类中的回滚方法名称;interceptor: 重试的拦截器名称,重试的时候可以配置一个拦截器;value:需要重试的异常类型,跟下面的 include 一致;include:包含的重试的异常类型;exclude:不包含的重试异常类型;label:用于统计的唯一标识;stateful​:标志表示重试是有状态的,也就是说,异常被重新抛出,重试策略是否会以相同的策略应用于具有相同参数的后续调用。如果是false,那么可重试的异常就不会被重新抛出。maxAttempts:重试次数;backoff:指定用于重试此操作的属性;listeners​:重试监听器bean名称;

配合上面的一些属性的使用,我们就可以达到通过注解简单来实现方法调用异常后的自动重试,非常好用。我们可以在执行重试方法的时候设置自定义的重试拦截器,如下所示,自定义重试拦截器需要实现MethodInterceptor​接口并实现invoke方法,不过要注意,如果使用了拦截器的话,那么方法上的参数就会被覆盖。

package com.example.demo.pid;import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;import org.springframework.retry.interceptor.RetryInterceptorBuilder;import org.springframework.retry.interceptor.RetryOperationsInterceptor;import org.springframework.retry.policy.SimpleRetryPolicy;import org.springframework.stereotype.Component;@Componentpublic class CustomRetryInterceptor implements MethodInterceptor {  @Override  public Object invoke(MethodInvocation invocation) throws Throwable {    RetryOperationsInterceptor build = RetryInterceptorBuilder.stateless()      .maxAttempts(2).backOffOptions(3000, 2, 1000).build();    return build.invoke(invocation);  }}

自定义回滚方法,我们还可以在重试几次依旧错误的情况,编写自定义的回滚方法。

@Retryable(value = Exception.class,    recover = "recover", maxAttempts = 2,    backoff = @Backoff(delay = 1000, multiplier = 2))  public String sayHello(String name){    return name + doSomething();  }  @Recover  public String recover(Exception e, String name) {    System.out.println("recover");    return "recover";  }

要注意:

重试方法必须要使用@Recover注解;返回值必须和被重试的函数返回值一致;参数中除了第一个是触发的异常外,后面的参数需要和被重试函数的参数列表一致;

上面代码中的@Backoff(delay = 1000, multiplier = 2)表示第一次延迟 1000ms 重试,后面每次重试的延迟时间都翻倍。

总结

阿粉今天给大家介绍了一下Spring​的@Retryable注解使用,并通过几个 demo 来带大家编写了自己重试拦截器以及回滚方法的时候,是不是感觉用起来会很爽,那还在等什么赶紧用起来吧,其中还有很多细节,只有自己真正的使用过才能体会到。

标签:

(责任编辑:news01)
世界热议:激情岁月——李承祥八十抒怀影集_关于激情岁月——李承祥八十抒怀影集介绍

世界热议:激情岁月——李承祥八十抒怀影集_关于激情岁月——李承祥八十抒怀影集介绍

1、激情岁月——李承祥八十抒怀影集,舞蹈人物画册。2、总策划冯英。3、中华书局2012年3月出版。4、为李...
05-04 13:50:34
全球看点:铁观音怎么喝减肥?喝决明子茶能减肥吗?

全球看点:铁观音怎么喝减肥?喝决明子茶能减肥吗?

茶叶是生活中最常见的碱性食品,喝茶有利于调节人体的酸碱平衡,具有排除体内多余水分和减肥的功效。那么铁
05-04 13:03:42
北京托运一台汽车到深圳多少钱

北京托运一台汽车到深圳多少钱

北京托运一台汽车到深圳多少钱?如果您想从北京把您的爱车运到深圳,您肯定想知道这将花费多少钱,这很正常
05-04 12:33:13
今年“五一”旅游为什么这么“热”?-世界资讯

今年“五一”旅游为什么这么“热”?-世界资讯

与春节假期相比,旅游度假属性更突出的“五一”才是旅游消费开启全面复苏后的第一个长假,客流大增是必...
05-04 12:16:41
昱能科技(688348.SH):近阶段接下来几年的目标就是要尽快往营收100亿的方向努力-环球简讯

昱能科技(688348.SH):近阶段接下来几年的目标就是要尽快往营收100亿的方向努力-环球简讯

格隆汇5月4日丨昱能科技(688348 SH)于2023年04月27日15:30-16:30召开2022年度暨2023年第一季度业绩说明会,
05-04 11:35:07
五一我在岗 郑州城管用劳动诠释城市之美

五一我在岗 郑州城管用劳动诠释城市之美

五一小长假期间,郑州市城市管理局干部职工岗位坚守,用辛勤劳动守护着这座城市。
05-04 11:11:08
楼市行情转淡 百强房企4月销售额环比下降17.4%-世界快看

楼市行情转淡 百强房企4月销售额环比下降17.4%-世界快看

【楼市行情转淡百强房企4月销售额环比下降17 4%】中指研究院数据显示,百强房企4月销售额环比下降17 4%,同
05-04 10:58:03
内蒙古房地产业高质量发展展览会开幕 全球热头条

内蒙古房地产业高质量发展展览会开幕 全球热头条

4月28日,以“转型升级与新发展模式”为主题的内蒙古房地产业高质量发展展览会正式启幕,我市设分会场同...
05-04 10:23:42
支持基础研究夯实创新根基 世界简讯

支持基础研究夯实创新根基 世界简讯

支持基础研究夯实创新根基---为健全完善上海基础研究布局体系,进一步营造有利于科学家和团队潜心开展基础
05-04 10:10:42
以音乐之名!泰安“网红”气质再出圈

以音乐之名!泰安“网红”气质再出圈

海报新闻记者田阳泰安报道从古至今,泰山的巍峨壮丽都让人心之神往。每年,都有大批游客慕名而来,祈愿岁月
05-04 09:34:06
【品牌】realme手机预热新代言人:演员吴磊

【品牌】realme手机预热新代言人:演员吴磊

今天上午,realme真我手机官方微博预热明天将介绍一位越级新伙伴。据了解realme这则预热是指明天将官宣真我
05-04 09:03:10
今年“五一”旅游为什么这么“热”? 全球热点

今年“五一”旅游为什么这么“热”? 全球热点

5月3日,中国文旅部披露的数据显示,2023年“五一”假期,全国国内旅游出游合计2 74亿人次,同比增长70 83%
05-04 08:57:47
“五一”假期消费爆棚 旅游餐饮文娱三大板块都很“挤”

“五一”假期消费爆棚 旅游餐饮文娱三大板块都很“挤”

北京首都机场T3航站楼附近有一个配套公园,是拍摄飞机起降的最佳地点。“五一”期间,机场吞吐量明显增...
05-04 08:14:21
福登社媒:伊蒂哈德的完美夜晚,恭喜我的哥们哈兰德 焦点热议

福登社媒:伊蒂哈德的完美夜晚,恭喜我的哥们哈兰德 焦点热议

直播吧5月4日讯在北京时间今天凌晨进行的英超第28轮补赛中,福登打进一球,帮助曼城主场3比0击败西汉姆。赛
05-04 07:13:17
资讯:西电1.8GW组件开标:最低1.53元/瓦

资讯:西电1.8GW组件开标:最低1.53元/瓦

4月28日,西安西电新能源有限公司2023年单晶光伏组件框架采购开标,共有26家企业投标,项目总规模在1 8GW。
05-04 06:21:25
《漫威蜘蛛侠RE》PS5版5月独立发布 售价约345元-每日看点

《漫威蜘蛛侠RE》PS5版5月独立发布 售价约345元-每日看点

索尼宣布,《漫威蜘蛛侠:重制版》将于5月推出PS5版,售价49 99美元(345元人民币)。有PS4版的玩家可以花1
05-04 04:51:44
新时代铝电解生产一线的技术尖兵_环球今日报

新时代铝电解生产一线的技术尖兵_环球今日报

兰州市总工会“中国梦·劳动美——凝心铸魂跟党走团结奋斗新征程”系列报道之四新时代铝电解生产一线的...
05-04 02:29:24
自重训练动作大全_自重

自重训练动作大全_自重

1、自重,汉语词汇。2、拼音:zìzhòng指谨言慎行﹐尊重自己的人格;自己重视。3、 ---------------
05-04 00:00:13
美国财政部保持季度债券销售规模不变,同时启动回购计划_环球新要闻

美国财政部保持季度债券销售规模不变,同时启动回购计划_环球新要闻

美国财政部周三表示,多数债券最早将于8月发行,比许多交易商预期的时间提前
05-03 21:59:51
环球新消息丨架子鼓好学吗_过来人说说架子鼓难学吗

环球新消息丨架子鼓好学吗_过来人说说架子鼓难学吗

欢迎观看本篇文章,小柴来为大家解答以上问题。架子鼓好学吗,过来人说说架子鼓难学吗很多人还不知道,现在
05-03 20:53:30
致敬劳动者!三代电力工程师赓续“劳动精神”

致敬劳动者!三代电力工程师赓续“劳动精神”

劳动铸就梦想,奋斗书写精彩。“五一”国际劳动节之际,全社会再次唱响“劳动最光荣”的最强音。新中国...
05-03 19:50:15
致敬坚守 拼搏奋斗详细内容 世界即时看

致敬坚守 拼搏奋斗详细内容 世界即时看

大家好,小太来为大家解答以上问题。致敬坚守拼搏奋斗很多人还不知道,现在让我们一起来看看吧!1、想必大
05-03 19:00:00
焦点播报:12月4日全国法制宣传日的由来_2018年12月4日全国法制宣传日主题

焦点播报:12月4日全国法制宣传日的由来_2018年12月4日全国法制宣传日主题

1、12月4日是第二个国家宪法日,也是第十五个法制宣传日。2、今年法制宣传活动的主题是“弘扬宪法精神,推
05-03 18:06:31
短讯!南京小西湖街区的破与立(上)丨破茧

短讯!南京小西湖街区的破与立(上)丨破茧

小西湖街区地处有“南京的根”之称的老城南,是南京28个历史风貌区之一。在2015年启动的小西湖城市更新...
05-03 16:58:59
中信证券:预计5月A股仍处于今年第二个关键做多窗口中 世界聚焦

中信证券:预计5月A股仍处于今年第二个关键做多窗口中 世界聚焦

中信证券5月3日表示,预计5月A股仍处于今年第二个关键做多窗口中,并将步入业绩驱动的行情阶段,投资者心态
05-03 15:57:40
即时:在1-3输给阿森纳之后,切尔西的积分停留在39分...

即时:在1-3输给阿森纳之后,切尔西的积分停留在39分...

在1-3输给阿森纳之后,切尔西的积分停留在39分!在少赛一轮的情况下领先降级区9分!球队接下来还有5轮比赛
05-03 15:08:13
“五一”假期出行报告:机票、火车票、酒店数据加速回温_环球快播

“五一”假期出行报告:机票、火车票、酒店数据加速回温_环球快播

【“五一”假期出行报告:机票、火车票、酒店数据加速回温】今年“五一”假期收官在即。中国在线旅游平...
05-03 14:20:20
失信人能坐飞机吗(经常坐飞机的人老得慢吗)|全球热门

失信人能坐飞机吗(经常坐飞机的人老得慢吗)|全球热门

1、运动是相对的,你做汽车火车感觉到速度快其实是因为路边的参照物在快速的变化,而做飞机。2、因为天上的
05-03 13:17:46
当前简讯:记者探访淄博公安护航平安十二时辰:人间烟火里的平安“淄”味

当前简讯:记者探访淄博公安护航平安十二时辰:人间烟火里的平安“淄”味

原标题:“五一”假期,本报记者探访淄博公安护航平安十二时辰——(引题)人间烟火里的平安“淄”味(...
05-03 12:15:41
全球新动态:五一假期前四天跨省游客占比23.6%,省内游客占比超76%

全球新动态:五一假期前四天跨省游客占比23.6%,省内游客占比超76%

5月1日,游客在大运河江苏无锡段的清名桥历史文化街区游览。新华社图据中国移动梧桐大数据统计,4月29日至5
05-03 11:15:43

为您推荐

精彩推送