作者:cndz 围观群众:666 更新于 标签:spring boot重处理Spring Retry
在开发中,我们经常会遇到一些不可避免的错误,例如网络故障、磁盘空间不足等等。而这些错误可能会导致我们的业务逻辑失败,获取这些错误重试就可以成功,为了确保业务流程正常运行,需要进行重试操作。而Spring Retry
就是为了解决这个问题而生的。
Spring Retry主要用于处理一些不稳定的操作,比如网络请求、数据库连接等。在这些场景下,我们可能需要尝试多次才能成功,而Spring Retry正是为此而生的。
下面是一些适合使用Spring Retry的场景:
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
//@EnableRetry 启用重处理注解
@EnableRetry
@SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
}
}
Spring Retry提供了非常简单易用的API,只需在需要重试的方法上添加注解即可。例如:
private Integer callNum = 0 ;//调用次数
@Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(delay = 1000))
public void test() throws Exception {
if(callNum == 0){
callNum++;
log.error("模拟失败情况,抛出异常,调用次数:{}",callNum);
throw new IllegalArgumentException("错误了");
}
log.info("重调用成功!:调用次数{}",callNum);
}
在上面的代码示例中,当内容抛出异常后,最多重试3次,每次重试间隔时间为1秒。下面为运行效果。重处理时未抛出异常。重处理成功。
简单解释下上面注解中常用值
value
抛出指定异常进行出重处理操作。include
同 value
一样,指定抛出异常后进行重处理,默认为空,默认为所有异常。exclude
指定不用用处理的异常,如RuntimeException,如果我们主动校验发现了异常。不需要重处理,需要指定此值。maxAttempts
该值指定最大重试次数,默认为3.
@backoff 重试补偿策略,默认使用@Backoff
value
返回固定多少毫秒后重试(默认为1000毫秒)
delay
返回延迟多少毫秒后重试(默认为0毫秒)multiplier
指定延迟的倍数,比如delay=5000l,multiplier=2时,第一次重试为5秒,第二次=上次延迟5秒乘以2倍10秒,第三次为上次延迟10秒乘以两倍20秒(上次延迟秒数乘以倍数
)注意:value与delay设置一个即可,如果有multiplier参数时,都会与multiplier结合使用。
当重试到达指定次数时,被注解的方法将被回调,可以在该方法中进行日志处理。需要注意的是发生的异常和入参类型一致时才会回调。
若retrable方法中抛出了多个异常,Recover就需要写多个,或者recover中异常为Exception可以拦截所有异常回调
@GetMapping("/test1")
@Retryable(value = Exception.class,maxAttempts = 2,backoff = @Backoff(delay = 5000))
public void test() throws Exception {
callNum++;
log.error("模拟失败情况,抛出异常,调用次数:{}",callNum);
throw new IllegalArgumentException("错误了");
}
@Recover
public void recover(Exception e){
log.error("recover回调");
}
执行结果如下:
然而,在实际应用中,我们往往需要更加灵活的重试策略,例如当遇到第一次重试时,我们需要将一些信息记录到日志中,或者在每次重试之前需要进行一些数据清理操作。这时,我们可以通过实现RetryCallback
和RecoveryCallback
接口来实现更加灵活的重试策略。例如:
public class MyRetryCallback implements RetryCallback<Void, Exception>, RecoveryCallback<Void> {
private int retryCount = 0;
@Override
public Void doWithRetry(RetryContext context) throws Exception {
try {
// do something
} catch (Exception e) {
retryCount++;
if (retryCount == 1) {
// log some info
}
throw e;
}
return null;
}
@Override
public Void recover(RetryContext context) throws Exception {
// do some recovery operations
return null;
}
}
上面的代码实现了一个自定义的RetryCallback
和RecoveryCallback
接口,当重试失败时,会记录一些信息到日志中,并进行恢复操作。
除了注解和RetryCallback
和RecoveryCallback
接口外,Spring Retry还提供了一些高级用法,例如:
Retryable
注解我们可以通过自定义Retryable
注解来实现更加灵活的重试策略。例如:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Retryable(include = {IllegalArgumentException.class},
exclude = {FileNotFoundException.class},
maxAttempts = 3, backoff = @Backoff(delay = 1000))
public @interface MyRetryable {
}
上面的代码定义了一个自定义的Retryable
注解,当方法抛出IllegalArgumentException
异常时,进行重试,最多重试3次,每次重试之间间隔1秒。而当方法抛出FileNotFoundException
异常时,则不进行重试。
RetryTemplate
我们可以通过自定义RetryTemplate
来实现更加灵活的重试策略。例如:
public class MyRetryTemplate extends RetryTemplate {
public MyRetryTemplate() {
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
retryPolicy.setMaxAttempts(3);
setRetryPolicy(retryPolicy);
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
backOffPolicy.setBackOffPeriod(1000);
setBackOffPolicy(backOffPolicy);
}
}
上面的代码定义了一个自定义的RetryTemplate
,最多重试3次,每次重试之间间隔1秒。
::: 提示 注意事项
在使用Spring Retry时,需要注意过多的重试可能会导致性能问题甚至加剧原始问题。确保为最大重试次数和重试之间的延迟设置适当的值。此外,请注意某些异常(如RuntimeException
)默认情况下会进行重试。如果这些异常不适用于您的用例,请考虑将其排除在外。
:::
在使用Spring Retry时,需要注意以下几点:
Spring Retry是一个非常好用的重试框架,它可以轻松地帮助我们解决重试的问题。通过使用注解、自定义RetryCallback
和RecoveryCallback
接口、自定义Retryable
注解和自定义RetryTemplate
,我们可以实现更加灵活的重试策略,从而为我们的应用带来更好的容错性和可靠性。