目录
一 . 引入依赖
二 . 在启用类或业务类上添加@EnableRetry注解启用重试机制(在启用类上添加全局有效 , 在业务类上添加仅当前有效)
三 . 使用@Retryable实现重试
四 . 使用@Recover执行补偿方法
五 . 测试及结果
六 . 常用属性说明
七 . 常见问题
在业务场景中 , 有时候会遇到异常后需要重复尝试的操作 , 例如调用三方接口 , 发送邮件/短信 , 推送消息等等 .
Spring 提供了Retry组件 , 很方便的解决了上述问题
项目源代码 : https://download.csdn.net/download/xingbaozhen1210/11384277
org.springframework.retry
spring-retry
1.2.4.RELEASE
org.aspectj
aspectjweaver
1.9.4
package cn.xing.demo.retry;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.retry.annotation.EnableRetry;
@SpringBootApplication
@EnableRetry//启用重试机制
public class RetryApplication {
public static void main(String[] args) {
SpringApplication.run(RetryApplication.class, args);
}
}
/** @Retryable() = @Retryable(maxAttempts = 3) , 出现任意异常后再重试2次 */
@Retryable()
public void work1() {
System.out.println("执行方法1 : " + LocalDateTime.now());
throw new RuntimeException();//模拟异常
}
/** 出现指定异常时(RuntimeException) , 再重试3次 , 每次延迟5s , 之后每次延迟翻倍*/
@Retryable(include = {RuntimeException.class}, maxAttempts = 4, backoff = @Backoff(delay = 2000L, multiplier = 2))
public void work2() {
System.out.println("执行方法2 : " + LocalDateTime.now());
throw new RuntimeException();//模拟异常
}
即使重试之后 , 仍然因为各种原因导致失败 , 这时候就可以在补偿方法中记录异常或采用其他措施
/** 出现指定异常时(NullPointerException) */
@Retryable(include = NullPointerException.class)
public void work3() {
System.out.println("执行方法3 : " + LocalDateTime.now());
throw new NullPointerException();//模拟异常
}
/** 当重试次数达到限定时 , 会执行@Recover注解的补偿方法 , 只有在入参与发生异常匹配时才会执行该补偿方法 */
@Recover
public void recover(NullPointerException e) {
System.out.println("执行补偿方法 : " + LocalDateTime.now());
}
package cn.xing.demo.retry;
import cn.xing.demo.retry.service.WorkService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class RetryTest {
@Autowired
private WorkService workService;
@Test
public void test1() {
workService.work1();
}
@Test
public void test2() {
workService.work2();
}
@Test
public void test3() {
workService.work3();
}
}
@Retryable
value : 指定发生的异常进行重试
include : 同value , 默认"" , 当exclude也为空时 , 所有异常都重试
exclude : 排除不重试的异常 , 默认"" , 当include也为空时 , 所有异常都重试
maxAttemps : 尝试次数 , 默认3 . 注意该值包含第一次正常执行的次数 , 即失败之后重新尝试2次 , 一共执行3次
backoff : 重试补偿机制 , 默认无 , 属性配置如下
@Backoff
delay : 延迟指定时间后(单位毫秒)重试
multiplier : 指定延迟的倍数 , 每次执行间隔加倍延迟 . 如delay=5000L,multiplier=2 , 第一次重 试为5S后 , 第二次为第一次的10S后 , 第三次为第二次的20S后
1 . maxAttemps 参数为尝试次数 , 而非重试次数 . 即=3时 , 会重试2次 , =4时会重试3次 , 因为它包括了首次正常执行的计数
2 . retry利用了Spring AOP的原理 , 所以底层采用了代理的技术 , 所有同一个类内调用会使代理失效
public void work1(){
work2();
}
@Retryable()//work2方法不会执行重试
public void work2(){
//...
}
3 . 有关非幂等的操作(如新增,修改等) , 不要使用重试 , 会影响数据一致性