Srping提供了失败重试功能Spring Retry,在网络不稳定的情况下,避免调用外部接口失败导致流程中断。也可以结合SpringCloudHystrix熔断一起使用。Spring Retry提供了自定义重试、回调等等。
SpringBoot项目想要使用Spring Retry需要在启动类Application上面加此注解
/**
* @author chengyanqi
* @date 2020/7/12 21:35
*/
@EnableRetry
@SpringBootApplication
@ComponentScan(basePackages = "com.chengyanqi")
@EnableAutoConfiguration
public class MySpringBootApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(MySpringBootApplication.class, args);
}
}
@Retryable注解可以加在方法上,也可以加在类上。加在类上时,此类中所有方法均有失败重试机制。
参数 | 说明 |
---|---|
value | 指定需要触发重试机制的异常 |
exclude | 和value一样,默认空,当exclude也为空时,所有异常都重试 |
maxAttempts | 重试次数,默认3,第一次执行也算在总次数中 |
backoff | 重试补偿机制,默认没有 |
delay | 每次重试等待的时间,毫秒 |
maxDelay | 最大延迟的时间,不设置默认为30秒钟。 |
multiplier | 重新发起延迟时间的基数。比如delay=100L,mutiplier=2,第一次重试延迟100ms,第二次重试延迟200ms,第三次400ms |
@Retryable(value = ClassNotFoundException.class, backoff = @Backoff(delay = 100L, multiplier = 2, maxDelay = 5000L))
public void retryTest() throws Exception {
System.out.println(count++);
throw new RuntimeException();
}
1
结束class java.lang.RuntimeException
value设置为ClassNotFoundException,抛出RuntimeException,没有进行重试。
@Retryable(value = RuntimeException.class, backoff = @Backoff(delay = 100L, multiplier = 2, maxDelay = 5000L))
public void retryTest() throws Exception {
System.out.println(++count);
throw new RuntimeException();
}
1
2
3
结束class java.lang.RuntimeException
value=RuntimeException.class,抛出RuntimeException。正常重新调用。
@Retryable(value = Exception.class, exclude = RuntimeException.class,backoff = @Backoff(delay = 100L, multiplier = 2, maxDelay = 5000L))
public void retryTest() throws Exception {
System.out.println(++count);
throw new RuntimeException();
}
1
结束class java.lang.RuntimeException
设置value为Exception所有异常。exclude为RuntimeException,抛出异常时,没有方法只执行了一次,没有进行重试
@Retryable(value = Exception.class,backoff = @Backoff(delay = 100L, multiplier = 2, maxDelay = 5000L))
public void retryTest() throws Exception {
System.out.println(++count);
throw new RuntimeException();
}
1
2
3
结束class java.lang.RuntimeException
maxAttemps为空,默认执行三次。修改为2再次执行。
@Retryable(value = Exception.class, maxAttempts = 2, backoff = @Backoff(delay = 100L, multiplier = 2, maxDelay = 5000L))
public void retryTest() throws Exception {
System.out.println(++count);
throw new RuntimeException();
}
1
2
结束class java.lang.RuntimeException
@Retryable(value = Exception.class, backoff = @Backoff(delay = 100L, multiplier = 1, maxDelay = 5000L))
public void retryTest() throws Exception {
SimpleDateFormat format = new SimpleDateFormat("ss秒SSS毫秒");
System.out.println("第"+ ++count +"次执行,时间:" +format.format(new Date()));
throw new RuntimeException();
}
第1次执行,时间:13秒111毫秒
第2次执行,时间:13秒212毫秒
第3次执行,时间:13秒312毫秒
结束class java.lang.RuntimeException
设置delay为100L,每隔100ms执行一次方法一次
@Retryable(value = Exception.class,maxAttempts=5, backoff = @Backoff(delay = 100L, multiplier = 3, maxDelay = 5000L))
public void retryTest() throws Exception {
SimpleDateFormat format = new SimpleDateFormat("ss秒SSS毫秒");
System.out.println("第"+ ++count +"次执行,时间:" +format.format(new Date()));
throw new RuntimeException();
}
第1次执行,时间:51秒596毫秒
第2次执行,时间:51秒697毫秒
第3次执行,时间:51秒998毫秒
第4次执行,时间:52秒898毫秒
第5次执行,时间:55秒598毫秒
结束class java.lang.RuntimeException
根据运行结果可以看出,multiplier设置为3,每次重试的次数为3的倍数×delay。
第一次100,第二次300,第三次900,第四次2700…
@Retryable(value = Exception.class,maxAttempts=10, backoff = @Backoff(delay = 100L, multiplier = 2, maxDelay = 300L))
public void retryTest() throws Exception {
SimpleDateFormat format = new SimpleDateFormat("ss秒SSS毫秒");
System.out.println("第"+ ++count +"次执行,时间:" +format.format(new Date()));
throw new RuntimeException();
}
第1次执行,时间:32秒094毫秒
第2次执行,时间:32秒195毫秒
第3次执行,时间:32秒395毫秒
第4次执行,时间:32秒695毫秒
第5次执行,时间:32秒996毫秒
第6次执行,时间:33秒296毫秒
第7次执行,时间:33秒596毫秒
第8次执行,时间:33秒897毫秒
第9次执行,时间:34秒197毫秒
第10次执行,时间:34秒497毫秒
结束class java.lang.RuntimeException
执行次数设置为10,倍数设置为2,等待时间为100ms。当我们设置maxDelay=300L时,可以从执行结果看出,每次重调时间间隔最大为300ms。
@Retryable(value = Exception.class,maxAttempts=3, backoff = @Backoff(delay = 100L, multiplier = 2, maxDelay = 300L))
public void retryTest() throws Exception {
SimpleDateFormat format = new SimpleDateFormat("ss秒SSS毫秒");
System.out.println("第" + ++count + "次执行,时间:" + format.format(new Date()));
throw new RuntimeException("自定义异常");
}
@Recover
public void recover(RuntimeException e) {
System.out.println("触发回调函数:" + e.getMessage());
}
第1次执行,时间:09秒230毫秒
第2次执行,时间:09秒332毫秒
第3次执行,时间:09秒532毫秒
触发回调函数:自定义异常
这是模拟异常场景,如果业务代码正常运行,不会执行@Recover的代码。下面模拟正常调用场景。
@Retryable(value = Exception.class,maxAttempts=3, backoff = @Backoff(delay = 100L, multiplier = 2, maxDelay = 300L))
public void retryTest() throws Exception {
SimpleDateFormat format = new SimpleDateFormat("ss秒SSS毫秒");
System.out.println("第" + ++count + "次执行,时间:" + format.format(new Date()));
if (count > 2)
return;
throw new RuntimeException("自定义异常");
}
@Recover
public void recover(RuntimeException e) {
System.out.println("触发回调函数:" + e.getMessage());
}
第1次执行,时间:22秒634毫秒
第2次执行,时间:22秒735毫秒
第3次执行,时间:22秒936毫秒