spring retry实现方法请求重试的使用步骤
作者:赵广陆 发布时间:2021-12-31 15:11:11
1 spring-retry是什么?
以往我们在进行网络请求的时候,需要考虑网络异常的情况,本文就介绍了利用spring-retry,是spring提供的一个重试框架,原本自己实现的重试机制,现在spring帮封装好提供更加好的编码体验。
2 使用步骤
2.1 引入maven库
代码如下(示例):
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
2.2 在spring启动类上开启重试功能
提示:添加@EnableRetry注解开启
@SpringBootApplication
@EnableRetry
public class SpringRetryDemoApplication {
public static SpringRetryAnnotationService springRetryAnnotationService;
public static SpringRetryImperativeService springRetryImperativeService;
public static TranditionalRetryService tranditionalRetryService;
@Autowired
public void setSpringRetryAnnotationService(SpringRetryAnnotationService springRetryAnnotationService) {
SpringRetryDemoApplication.springRetryAnnotationService = springRetryAnnotationService;
}
@Autowired
public void setSpringRetryImperativeService(SpringRetryImperativeService springRetryImperativeService) {
SpringRetryDemoApplication.springRetryImperativeService = springRetryImperativeService;
}
@Autowired
public void setTranditionalRetryService(TranditionalRetryService tranditionalRetryService) {
SpringRetryDemoApplication.tranditionalRetryService = tranditionalRetryService;
}
public static void main(String[] args) {
SpringApplication.run(SpringRetryDemoApplication.class, args);
springRetryAnnotationService.test();
springRetryImperativeService.test();
tranditionalRetryService.test();
}
}
2.3 公共业务代码
@Service
@Slf4j
public class CommonService {
public void test(String before) {
for (int i = 0; i < 10; i++) {
if (i == 2) {
log.error("{}:有异常哦,我再试多几次看下还有没异常", before);
throw new RuntimeException();
}
log.info("{}:打印次数: {}", before, i + 1);
}
}
public void recover(String before) {
log.error("{}:还是有异常,程序有bug哦", before);
}
}
2.4 传统的重试做法
@Service
@Slf4j
public class TranditionalRetryService {
@Autowired
CommonService commonService;
public void test() {
// 定义重试次数以及重试时间间隔
int retryCount = 3;
int retryTimeInterval = 3;
for (int r = 0; r < retryCount; r++) {
try {
commonService.test("以前的做法");
} catch (RuntimeException e) {
if (r == retryCount - 1) {
commonService.recover("以前的做法");
return;
}
try {
Thread.sleep(retryTimeInterval * 1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
}
2.5 使用spring-retry的命令式编码
2.5.1 定义重试 *
提示:监听重试过程的生命周期
@Slf4j
public class MyRetryListener extends RetryListenerSupport {
@Override
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
log.info("监听到重试过程关闭了");
log.info("=======================================================================");
}
@Override
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
log.info("监听到重试过程错误了");
}
@Override
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
log.info("=======================================================================");
log.info("监听到重试过程开启了");
return true;
}
}
2.5.2 定义重试配置
提示:配置RetryTemplate重试模板类
@Configuration
public class RetryConfig {
@Bean
public RetryTemplate retryTemplate() {
// 定义简易重试策略,最大重试次数为3次,重试间隔为3s
RetryTemplate retryTemplate = RetryTemplate.builder()
.maxAttempts(3)
.fixedBackoff(3000)
.retryOn(RuntimeException.class)
.build();
retryTemplate.registerListener(new MyRetryListener());
return retryTemplate;
}
}
2.5.3 命令式编码
@Service
@Slf4j
public class SpringRetryImperativeService {
@Autowired
RetryTemplate retryTemplate;
@Autowired
CommonService commonService;
public void test() {
retryTemplate.execute(
retry -> {
commonService.test("命令式");
return null;
},
recovery -> {
commonService.recover("命令式");
return null;
}
);
}
}
2.6使用spring-retry的注解式编码
@Service
@Slf4j
public class SpringRetryAnnotationService {
@Autowired
CommonService commonService;
/**
* 如果失败,定义重试3次,重试间隔为3s,指定恢复名称,指定 *
*/
@Retryable(value = RuntimeException.class, maxAttempts = 3, backoff = @Backoff(value = 3000L), recover = "testRecover", listeners = {"myRetryListener"})
public void test() {
commonService.test("注解式");
}
@Recover
public void testRecover(RuntimeException runtimeException) {
commonService.recover("注解式");
}
}
3 SpringBoot整合spring-retry
我们使用SpringBoot来整合spring-retry组件实现重试机制。
3.1 添加@EnableRetry注解
在主启动类Application上添加@EnableRetry注解,实现对重试机制的支持
@SpringBootApplication
@EnableRetry
public class RetryApplication {
public static void main(String[] args) {
SpringApplication.run(RetryApplication.class, args);
}
}
注意:@EnableRetry也可以使用在配置类、ServiceImpl类、方法上
3.2 接口实现
注意:接口类一定不能少,在接口类中定义你需要实现重试的方法,否则可能会无法实现重试功能
我的测试接口类如下:
public interface RetryService { public String testRetry() throws Exception;}
3.3 添加@Retryable注解
我们针对需要实现重试的方法上添加@Retryable
注解,使该方法可以实现重试,这里我列出ServiceImpl
中的一个方法:
@Service
public class RetryServiceImpl implements RetryService {
@Override
@Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000,multiplier = 1.5))
public String testRetry() throws Exception {
System.out.println("开始执行代码:"+ LocalTime.now());
int code = 0;
// 模拟一直失败
if(code == 0){
// 这里可以使自定义异常,@Retryable中value需与其一致
throw new Exception("代码执行异常");
}
System.out.println("代码执行成功");
return "success";
}
}
说明:@Retryable配置元数据情况:
value :针对指定抛出的异常类型,进行重试,这里指定的是Exception
maxAttempts :配置最大重试次数,这里配置为3次(包含第一次和最后一次)
delay: 第一次重试延迟间隔,这里配置的是2s
multiplier :每次重试时间间隔是前一次几倍,这里是1.5倍
3.4 Controller测试代码
@RestController
@RequestMapping("/test")
public class TestController {
// 一定要注入接口,通过接口去调用方法
@Autowired
private RetryService retryService;
@GetMapping("/retry")
public String testRetry() throws Exception {
return retryService.testRetry();
}
}
3.5 发送请求
发送请求后,我们发现后台打印情况,确实重试了3次,并且在最后一次重试失败的情况下,才抛出异常,具体如下(可以注意下时间间隔)
3.6 补充:@Recover
一般情况下,我们重试最大设置的次数后,仍然失败抛出异常,我们会通过全局异常处理类进行统一处理,但是我们其实也可以自行处理,可以通过@Recover
注解来实现,具体如下:
@Service
public class RetryServiceImpl implements RetryService {
@Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000,multiplier = 1.5))
public String testRetry() throws Exception {
System.out.println("开始执行代码:"+ LocalTime.now());
int code = 0;
if(code == 0){
// 这里可以使自定义异常,@Retryable中value需与其一致
throw new Exception("代码执行异常");
}
System.out.println("代码执行成功");
return "success";
}
/**
* 最终重试失败处理
* @param e
* @return
*/
@Recover
public String recover(Exception e){
System.out.println("代码执行重试后依旧失败");
return "fail";
}
}
注意:
1)@Recover的方法中的参数异常类型需要与重试方法中一致
2)该方法的返回值类型与重试方法保持一致
再次测试如下(发现不会再抛出异常)
来源:https://blog.csdn.net/ZGL_cyy/article/details/125668526
猜你喜欢
- 这篇文章主要介绍了Java实现TCP/IP协议的收发数据(服务端)代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参
- 一、是什么当下很多公司都采取前后端分离的开发模式,前端和后端的工作由不同的工程师完成。在这种开发模式下,维持一份及时更新且完整的 Rest
- 原理解析:利用RandomAccessFile在本地创建一个随机访问文件,文件大小和服务器要下载的文件大小相同。 根据线程的数量(假设有三个
- 引言前边两章说了点基础的,从这章开始,我们挖挖源码。看看RocketMQ是怎么工作的。首先呢,这个生产者就是送孩子去码头的家长,孩子们呢,就
- 建造者模式概述建造者模式(Builder Pattern)属于创建型模式。它是将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同
- @ApiModel使用场景在实体类上边使用,标记类时swagger的解析类概述提供有关swagger模型的其它信息,类将在操作中用作类型时自
- 本文讲述了在Java中如何创建和结束线程的最基本方法,只针对于Java初学者。一些高级知识如线程同步、调度、线程池等内容将会在后续章节中逐步
- 介绍在分布式系统、微服务架构大行其道的今天,服务间互相调用出现失败已经成为常态。如何处理异常,如何保证数据一致性,成为微服务设计过程中,绕不
- 1.char数组(字符数组)->字符串可以通过:使用String.copyValueOf(charArray)函数实现。举例:char
- 1.官方地址:http://mybatis.plus/guide/generator.html#%E4%BD%BF%E7%94%A8%E6%
- Map是键值对的集合,又叫作字典或关联数组等,是最常见的数据结构之一。在java如何让一个map按value排序呢? 看似简单,但却不容易!
- 上一章节回顾:Netty分布式源码分析监听读事件概述pipeline, 顾名思义, 就是管道的意思, 在net
- 本文实例讲述了Java实现Http工具类的封装操作。分享给大家供大家参考,具体如下:http工具类的实现:(通过apache包)第一个类im
- 前言java 10 引进一种新的闪闪发光的特性叫做局部变量类型推断。听起来很高大上吧?它是什么呢? 下面的两个情景是我们作为 Java 开发
- 芬兰数学家因卡拉花费3个月设计出了世界上迄今难度最大的数独游戏,而且它只有一个答案。因卡拉说只有思考能力最快、头脑最聪明的人才能破解这个游戏
- pom.xml<dependency> <groupId>org.springframework.bo
- Pager.javapackage pers.kangxu.datautils.common;import java.io.Serializ
- 模拟ThreadLocal类实现:线程范围内的共享变量,每个线程只能访问他自己的,不能访问别的线程。package com.ljq.test
- 1. List1.1 List 的常见方法方法描述boolean add(E e)尾插 evoid add(int index, E ele
- @ApiImplicitParam作用在方法上,表示单独的请求参数参数name:参数名。value:参数的具体意义,作用。required: