学海无涯,旅“途”漫漫,“途”中小记,如有错误,敬请指出,在此拜谢!
在日常的开发中,有些场景,我们需要重试某个方法。比如当进行网络调用时,由于网络波动导致无法访问,需要重试几次。
一、github
https://github.com/spring-projects/spring-retry
二、使用方式
1、Spring-Boot
1.引入依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
2.启动文件引入@EnableRetry标签,比如
@SpringBootApplication
@EnableWebMvc
@EnableScheduling
@EnableRetry//开启重试机制标签
public class MytestApplication {
public static void main(String[] args) {
SpringApplication.run(MytestApplication.class, args);
}
}
3.需要重试的方法中,增加@Retryable标签,比如
/**
* 待重试的方法
*
* @param dto 重试传输dto
* @author lin
* @since 2019年9月24日
* <p>
* value:为指定重试的异常,只有该异常才会重试,如果多个异常重试,可以写做value = {RetryException.class,Exception.class}
* maxAttempts: 为重试次数,默认为3次
* @Backeoff中的标签
* delay: 延迟时间(单位为毫秒,默认为0毫秒)
* multiplier:延迟间隔倍率,比如如果定义延迟为1秒,延迟倍率为2,则第一次重试间隔1秒,第二次2秒,第三次4秒,依次类推
* maxDelay:最大间隔时间
*/
@Retryable(value = RetryException.class, maxAttempts = 5, backoff = @Backoff(delay = 1000, multiplier = 2))
public void handle(RetryTransferDto dto) {
log.info("正在处理消息,当前次数第{}次,消息为{}", dto.getCount(), dto.getMessage());
if (true) { // 模拟失败
dto.setCount(dto.getCount() + 1);
dto.setMessage(dto.getMessage() + " haha ");
throw new RetryException("消息处理失败,当前次数第" + dto.getCount() + "次,消息为" + dto.getMessage());
}
}
此处博主为了方便计数,增加了一个自定义的传输类RetryTransferDto,类的具体内容如下
import lombok.Data;
/**
* 重试传输dto
*
* @author lin
* @since 2019年9月24日
*/
@Data
public class RetryTransferDto {
// 重试次数
private int count = 0;
// 重试内容
private String message;
}
4.如果在最后一次重试报错后,想进入特定方法执行某些操作(比如写日志等),可以使用@Recover标签,例如
/**
* 重试达到指定次数时,进入此方法
*
* @author lin
* @since 2019年9月24日
*/
@Recover
public void recover(RetryException e) {
log.error("重试达到指定测试", e);
}
5.日志输出如下所示
2019-09-24 10:49:28.572 INFO 2416 --- [ main] com.lin.mytest.retry.RetryService : 正在处理消息,当前次数第1次,消息为haha
2019-09-24 10:49:29.575 INFO 2416 --- [ main] com.lin.mytest.retry.RetryService : 正在处理消息,当前次数第2次,消息为haha haha
2019-09-24 10:49:31.576 INFO 2416 --- [ main] com.lin.mytest.retry.RetryService : 正在处理消息,当前次数第3次,消息为haha haha haha
2019-09-24 10:49:35.577 INFO 2416 --- [ main] com.lin.mytest.retry.RetryService : 正在处理消息,当前次数第4次,消息为haha haha haha haha
2019-09-24 10:49:43.577 INFO 2416 --- [ main] com.lin.mytest.retry.RetryService : 正在处理消息,当前次数第5次,消息为haha haha haha haha haha
2019-09-24 10:49:43.582 ERROR 2416 --- [ main] com.lin.mytest.retry.RetryService : 重试达到指定测试
org.springframework.retry.RetryException: 消息处理失败,当前次数第6次,消息为haha haha haha haha haha haha
at com.lin.mytest.retry.RetryService.handle(RetryService.java:33) ~[classes/:na]
......
三、注意事项
1.因为Spring-Retry原理是切面操作,所以pom依赖中也需要有aop的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.因为是切面操作,所以待重试方法,不能是当前类中调用的方法。打个比方,A类中有方法a和方法b,方法a调用方法b时,在方法b上增加重试机制,此重试方法失效。
3.标签中maxAttempts、delay、multiplier等参数,需要是常量。如果想动态从yml或者properties的配置文件中获取,请使用对应的Expression参数。比如
/**
* 待重试的方法
*
* @param dto 重试传输dto
* @author lin
* @since 2019年9月24日
* <p>
* value:为指定重试的异常,只有该异常才会重试,如果多个异常重试,可以写做value = {RetryException.class,Exception.class}
* maxAttemptsExpression: 为重试次数,默认为3次
* Backeoff中的标签
* delayExpression: 延迟时间(单位为毫秒,默认为0毫秒)
* multiplierExpression:延迟间隔倍率,比如如果定义延迟为1秒,延迟倍率为2,则第一次重试间隔1秒,第二次2秒,第三次4秒,依次类推
* maxDelayExpression:最大间隔时间
*/
@Retryable(value = RetryException.class, maxAttemptsExpression = "${retry.attempts}", backoff = @Backoff(delayExpression = "${retry.delay}", multiplierExpression = "${retry.multiplier}"))
public void handle(RetryTransferDto dto) {
log.info("从配置文件获取参数,正在处理消息,当前次数第{}次,消息为{}", dto.getCount(), dto.getMessage());
if (true) { // 模拟失败
dto.setCount(dto.getCount() + 1);
dto.setMessage(dto.getMessage() + " haha ");
throw new RetryException("从配置文件获取参数,消息处理失败,当前次数第" + dto.getCount() + "次,消息为" + dto.getMessage());
}
}
四、我的测试代码
码云:
https://gitee.com/doubletreelin/mytest.git