01-Spring实现重试和降级机制

主要用于在模块调用中,出现失败、异常情况下,仍需要进行重复调用。并且在最终调用失败时,可以采用降级措施,返回一般结果。

1、重试机制

我们采用spring 提供的retry 插件,其原理采用aop机制,所以需要额外引入starter-aop包

1、依赖引入

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId>
</dependency>

2、在主启动类或者需要重试的方法所在的类上添加注解@EnableRetry

3、在需要重试的方法上增加注解 @Retryable,表示该方法需要重试。可以定义在接口的抽象方法上,也可以定义在实际的具体方法上。

public interface RetryService {/*** 指定异常CustomRetryException重试,重试最大次数为4(默认是3),重试补偿机制间隔200毫秒* 还可以配置exclude,指定异常不重试,默认为空* @return result* @throws CustomRetryException 指定异常*/@Retryable(value = {CustomRetryException.class},maxAttempts = 4,backoff = @Backoff(200))String retry() throws CustomRetryException;
}

@Retryable注解参数说明:

maxAttempts :最大重试次数,默认为3,如果要设置的重试次数为3,可以不写;

value:抛出指定异常才会重试,支持多异常

include:和value一样,默认为空,当exclude也为空时,默认所以异常

exclude:指定不处理的异常

backoff:重试等待时间策略,默认使用@Backoff的value默认为1000L,我们设置为200L。

@Backoff注解中的参数说明:

value:隔多少毫秒后重试,默认为1000L;

delay:和value一样,但是默认为0;

multiplier(指定延迟倍数)默认为0,表示固定暂停1秒后进行重试,如果把multiplier设置为1.5,则第一次重试为2秒,第二次为3秒,第三次为4.5秒。

④可以同时在同一个类中使用@Recover来处理N次处理后都没有成功后需要处理的事情

可以在指定方法上标记@Recover来开启重试失败后调用的方法(注意,需跟重处理方法在同一个类中)

3e6b29cabf1d44328c04240da2b9e781.png

2、请求降级

使用@Recover实现降级措施

当重试到达指定次数时,被注解的方法将被回调,可以在该方法中进行日志处理。需要注意的是发生的异常和入参类型一致时才会回调。

@Retryable和@Recover修饰的方法要在同一个类中,且被@Retryable 标记的方法不能有返回值,这样Recover方法才会生效。

/*** value:抛出指定异常才会重试* include:和value一样,默认为空,当exclude也为空时,默认所有异常* exclude:指定不处理的异常* maxAttempts:最大重试次数,默认3次* backoff:重试等待策略,* 默认使用@Backoff,@Backoff的value默认为1000L,我们设置为2000; 以毫秒为单位的延迟(默认 1000)* multiplier(指定延迟倍数)默认为0,表示固定暂停1秒后进行重试,如果把multiplier设置为1.5,则第一次重试为2秒,第二次为3秒,第三次为4.5秒。* @param code* @return* @throws Exception*/@Override@Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(delay = 2000,multiplier = 1.5))public int testRetry(int code) throws Exception{System.out.println("test被调用,时间:"+ LocalTime.now());if (code==0){throw new Exception("情况不对头!");}System.out.println("test被调用,情况对头了!");return 200;} /*** Spring-Retry还提供了@Recover注解,用于@Retryable重试失败后处理方法。* 如果不需要回调方法,可以直接不写回调方法,那么实现的效果是,重试次数完了后,如果还是没成功没符合业务判断,就抛出异常。* 可以看到传参里面写的是 Exception e,这个是作为回调的接头暗号(重试次数用完了,还是失败,我们抛出这个Exception e通知触发这个回调方法)。* 注意事项:* 方法的返回值必须与@Retryable方法一致* 方法的第一个参数,必须是Throwable类型的,建议是与@Retryable配置的异常一致,其他的参数,需要哪个参数,写进去就可以了(@Recover方法中有的)* 该回调方法与重试方法写在同一个实现类里面** 由于是基于AOP实现,所以不支持类里自调用方法* 如果重试失败需要给@Recover注解的方法做后续处理,那这个重试的方法不能有返回值,只能是void* 方法内不能使用try catch,只能往外抛异常* @Recover注解来开启重试失败后调用的方法(注意,需跟重处理方法在同一个类中),此注解注释的方法参数一定要是@Retryable抛出的异常,否则无法识别,可以在该方法中进行日志处理。* @param e* @param code* @return*/@Recoverpublic int recover(Exception e, int code){System.out.println("回调方法执行!!!!");//记日志到数据库 或者调用其余的方法System.out.println("异常信息:"+e.getMessage());return 400;} 

3、 RetryTemplate

对每个方法上进行注解定义以及对应降低方法定义,过于繁琐。

spring 提供 retryTemplate 的bean对象,定义一个可重试、降级的代理对象。

RetryTemplate提供了RetryOperations的一种具体实现。它被认为是从中创建bean的良好做法。

1、定义retryTemplate对象

    @Bean@ConditionalOnMissingBeanpublic RetryTemplate retryTemplate(){final SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy();simpleRetryPolicy.setMaxAttempts(4);
​final FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();fixedBackOffPolicy.setBackOffPeriod(1000L);
​return RetryTemplate.builder().customPolicy(simpleRetryPolicy).customBackoff(fixedBackOffPolicy).retryOn(CustomRetryException.class).build();}

 2、使用retryTemplate

@Autowiredpivate RetryTemplate retryTemplate;
​@Testvoid retryWithoutAnnotation(){try {String message = retryTemplate.execute(x -> retryService.retryWithoutAnnotation());log.info("message = "+message);} catch (CustomRetryException e) {log.error("Error while executing test {}",e.getMessage());}}

3、RecoveryCallback 降级

execute时,可以选择输入RecoveryCallback回调,确定重试结束后,仍然出现异常的recovery行为。自定义方法如下:

@Slf4j
public class CustomRecoveryCallback implements RecoveryCallback<String> {
​@Overridepublic String recover(RetryContext retryContext) throws Exception {log.info("Default Retry service test,total retry {}",retryContext.getRetryCount());return "Error Class :: " + retryContext.getLastThrowable().getClass().getName();}
}

4、RetryListenerSupport生命周期控制

如果我们想在重试整个生命周期中,按照不同的阶段设置一些事件监听处理机制,那怎么办呢?设置自定义的RetryListenerSupport能帮助到我们。我们继承RetryListenerSupport,并重新Override close 、onError、open方法,这三个方法分别表示

  • 所有重试结束时 close
  • 每一次重试发生异常时 onError
  • 重试正式开始前 open
@Slf4j
public class DefaultListenerSupport extends RetryListenerSupport {
​@Overridepublic <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {log.info("DefaultListenerSupport close");super.close(context, callback, throwable);}
​@Overridepublic <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {log.info("DefaultListenerSupport onError");super.onError(context, callback, throwable);}
​@Overridepublic <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {log.info("DefaultListenerSupport open");return super.open(context, callback);}
}

 并且在构造RetryTemaplate时候,设置withListener字段。

@Bean
@ConditionalOnMissingBean
public RetryListenerSupport retryListenerSupport(){return new DefaultListenerSupport();
}
​
@Bean
@ConditionalOnMissingBean
public RetryTemplate retryTemplate(RetryListenerSupport retryListenerSupport){
​...return RetryTemplate.builder().customPolicy(simpleRetryPolicy).customBackoff(fixedBackOffPolicy).withListener(retryListenerSupport).retryOn(CustomRetryException.class).build();
}

 

 

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

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

相关文章

SERVLET间通信

在Web应用程序中,应用程序的servlet等各种组件之间可能需要通信以便处理客户机请求。例如,假设Web应用程序中有一个servlet显示组织的版权信息。您可以使用各种servelt通信技术将此servlet的内容纳入到需要显示版权信息的所有其他应用程序servlet中。同样,如果处理请求时发生…

基于JavaWeb的网上订餐项目

点击以下链接获取源码&#xff1a; https://download.csdn.net/download/qq_64505944/88825723?spm1001.2014.3001.5503 Java项目-16 浏览商品&#xff0c;会员登录&#xff0c;添加购物车&#xff0c;进行配送等功能 文件代码功能介绍 1.Src下的java文件存放的我们后端的…

JDK新特性

JDK新特性 函数式接口和Lambda 表达式Stream流操作新日期API操作其他新特性 Lambda 是一个匿名函数&#xff0c;我们可以把 Lambda表达式理解为是一段可以传递的代码&#xff08;将代码 像数据一样进行传递&#xff09;。可以写出更简洁、更 灵活的代码。作为一种更紧凑的代码…

15000+POC漏洞扫描工具

0x01 工具介绍 scan4all拥有15000PoC漏洞扫描&#xff0c;23种应用弱口令爆破&#xff0c;7000Web指纹&#xff0c;146种协议&#xff0c;90000规则Port扫描。集成 vscan、nuclei、ksubdomain、subfinder等&#xff0c;充分自动化进行扫描。是一款Fuzz、HW打点、BugBounty神器…

CSP-202009-2-风险人群筛查

CSP-202009-2-风险人群筛查 解题思路 检查是否经过高危区 (x > x1) && (x < x2) && (y > y1) && (y < y2) 检查坐标是否在高危区域内&#xff0c; !isPassed 确保仅在第一次经过高危区域时增加 pass 计数。如果条件成立&#xff0c;表示…

java设计模式之中介者模式

中介者模式&#xff08;Mediator Pattern&#xff09; 基本介绍 中介者模式&#xff0c;用一个中介对象来封装一系列的对象交互。中介者使各个对象不需要显式地相互引用&#xff0c;从而使其解耦松散。而且可以独立地改变它们之间的交互。中介者模式属于行为型模式。比如MVC模…

C#,欧拉常数(Euler Constant)的算法与源代码

1 欧拉常数 欧拉常数最先由瑞士数学家莱昂哈德 欧拉 (Leonhard Euler) 在1735年发表的文章《De Progressionibus harmonicus observationes》中定义。欧拉曾经使用γ作为它的符号&#xff0c;并计算出了它的前6位&#xff0c;1761年他又将该值计算到了16位 。 欧拉常数最先由瑞…

2/10 BFS初探

其实在我看来解决全排列问题&#xff0c;核心还是顺序&#xff0c;想清楚结束条件&#xff0c;然后输出&#xff0c;以n3为例 #include<iostream> using namespace std; const int N 10; int path[N];//保存序列 int state[N];//数字是否被用过 int n; void dfs(int u) …

ubuntu彻底卸载cuda 重新安装cuda

sudo apt-get --purge remove "*cublas*" "*cufft*" "*curand*" \"*cusolver*" "*cusparse*" "*npp*" "*nvjpeg*" "cuda*" "nsight*" cuda10以上 cd /usr/local/cuda-xx.x/bin/ s…

Mac电脑清空特别大型旧文件如何一键清理?

在我们的数字生活中&#xff0c;Mac电脑常常承载着大量个人资料和重要文件。但当我们决定把自己的Mac送给亲人或朋友使用时&#xff0c;面临的首要任务便是彻底且高效地清空所有个人数据&#xff0c;以保证隐私安全。传统的删除方法虽然简单&#xff0c;但往往不能彻底清除所有…

问题:2、计算机网络的目标是实现________。 #媒体#知识分享

问题&#xff1a;2、计算机网络的目标是实现________。 A&#xff0e;数据处理 B&#xff0e;信息传输与数据处理 C&#xff0e;资源共享与信息传输 D&#xff0e;文献查询 参考答案如图所示

c语言中的隐式类型转换

数据类型转化 我们在实际编程中&#xff0c;不管你是有意的还是无意的&#xff0c;有时候都会让两个不同类型的数据参与运算&#xff0c;编译器为了能够生成CPU可以正常 执行的指令&#xff0c;往往会对数据做类型转换&#xff0c;将两个不同类型的数据转换成同一种数据类型。…

《CSS 简易速速上手小册》第1章:CSS 基础入门(2024 最新版)

文章目录 1.1 CSS 语法和选择器&#xff1a;挑选你的画笔1.1.1 基础知识1.1.2 重点案例&#xff1a;创建一个响应式导航菜单1.1.3 拓展案例 1&#xff1a;为特定链接添加图标1.1.4 拓展案例 2&#xff1a;创建一个简单的问答折叠面板 1.2 盒模型的基础&#xff1a;构建你的乐高…

Redis -- 渐进式遍历

家&#xff0c;是心的方向。不论走多远&#xff0c;总有一盏灯为你留着。桌上的碗筷多了几双&#xff0c;笑声也多了几分温暖。家人团聚&#xff0c;是最美的风景线。时间&#xff1a;2024年 2月 8日 12:51:20 目录 前言 语法 示例 前言 试想一个场景,那就是在key非常多的…

字节跳动官方出品AI,白嫖使用GPT4!

关注我&#xff0c;紧跟本系列专栏文章&#xff0c;咱们下篇再续&#xff01; 作者简介&#xff1a;魔都技术专家兼架构&#xff0c;多家大厂后端一线研发经验&#xff0c;各大技术社区头部专家博主&#xff0c;编程严选网创始人。具有丰富的引领团队经验&#xff0c;深厚业务架…

《CSS 简易速速上手小册》第8章:CSS 性能优化和可访问性(2024 最新版)

文章目录 8.1 CSS 文件的组织和管理8.1.1 基础知识8.1.2 重点案例&#xff1a;项目样式表结构8.1.3 拓展案例 1&#xff1a;使用BEM命名规范8.1.4 拓展案例 2&#xff1a;利用 Sass 混入创建响应式工具类 8.2 提高网页加载速度的技巧8.2.1 基础知识8.2.2 重点案例&#xff1a;图…

Google刚刚推出了图神经网络Tensorflow-GNN

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Vue源码系列讲解——虚拟DOM篇【四】(优化更新子节点)

目录 1. 前言 2. 优化策略介绍 3. 新前与旧前 4. 新后与旧后 5. 新后与旧前 6. 新前与旧后 7. 回到源码 8. 总结 1. 前言 在上一篇文章中&#xff0c;我们介绍了当新的VNode与旧的oldVNode都是元素节点并且都包含子节点时&#xff0c;Vue对子节点是 先外层循环newChil…

最佳视频转换器软件:2024年视频格式转换的选择

我们生活在一个充满数字视频的世界&#xff0c;但提供的内容远不止您最喜欢的流媒体服务目录。虽然我们深受喜爱的设备在播放各种自制和下载的视频文件方面变得越来越好&#xff0c;但在很多情况下您都需要从一种格式转换为另一种格式。 经过大量测试&#xff0c; 我们尝试过…

《CSS 简易速速上手小册》第5章:CSS 动画与过渡(2024 最新版)

文章目录 5.1 CSS 过渡基础&#xff1a;网页的微妙舞步5.1.1 基础知识5.1.2 重点案例&#xff1a;按钮悬停效果5.1.3 拓展案例 1&#xff1a;渐变显示导航菜单5.1.4 拓展案例 2&#xff1a;动态调整元素大小 5.2 关键帧动画&#xff1a;编排你的网页芭蕾5.2.1 基础知识5.2.2 重…