SpringRetry入门使用
本文基于spring-retry:1.2.5.RELEASE
依赖
java
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
@Retryable
- 在需要被重试的方法上加上@Retryable注解即可, 默认重试3次, 每次间隔1s, 如下案例
java
@Service
public class ErrorService {
@Retryable
public void throwRunEx() {
System.out.println("throwRunEx executed ==========> " + System.currentTimeMillis());
throw new RuntimeException("this is a test runtime exception!");
}
}
public class RetryTest extends BaseTest {
@Autowired
private ErrorService errorService;
@Test
public void testRetry() {
errorService.throwRunEx();
}
}
// 执行结果, 可以看到方法被重试了3次, 每次间隔1s
throwRunEx executed ==========> 1686458391279
throwRunEx executed ==========> 1686458392292
throwRunEx executed ==========> 1686458393292
java.lang.RuntimeException: this is a test runtime exception!
at com.pingan.lcloud.demo.service.ErrorService.throwRunEx(ErrorService.java:12)
- 该注解支持指定配置, 可以指定异常类型, 重试次数, 以及延迟时间(毫秒)
java
@Retryable(include = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 100))
// @Retryable(include = Exception.class, maxAttemptsExpression = "${retry.maxAttempts}",
// backoff = @Backoff(delayExpression = "${retry.maxDelay}"))
public void throwRunEx(String arg) {
System.out.printf("throwRunEx executed, arg: %s, time: %d%n", arg, System.currentTimeMillis());
throw new RuntimeException("this is a test runtime exception!");
}
@Recover
- 当@Retryable因指定异常重试达到最大次数后, 会调@Recover方法(就不会再抛出异常了)
java
@Service
public class ErrorService {
@Retryable(include = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 100))
// @Retryable(include = Exception.class, maxAttemptsExpression = "${retry.maxAttempts}",
// backoff = @Backoff(delayExpression = "${retry.maxDelay}"))
public void throwRunEx(String arg) {
System.out.printf("throwRunEx executed, arg: %s, time: %d%n", arg, System.currentTimeMillis());
throw new RuntimeException("this is a test runtime exception!");
}
@Recover
public void recover(Exception e, String arg) {
System.out.printf("recover executed, error: %s, arg: %s, time: %d%n", e.getMessage(), arg, System.currentTimeMillis());
}
}
// 执行结果
throwRunEx executed, arg: newBee, time: 1686459024642
throwRunEx executed, arg: newBee, time: 1686459025646
throwRunEx executed, arg: newBee, time: 1686459026649
recover executed, error: this is a test runtime exception!, arg: newBee, time: 1686459026649
RetryTemplate
- spring-retry提供了RetryOperations接口来支持以api的形式使用该框架, RetryTemplate是RetryOperations的默认实现
- RetryCallback即是每次重试时需要插入的业务逻辑
java
public interface RetryOperations {
<T, E extends Throwable> T execute(RetryCallback<T, E> var1) throws E;
<T, E extends Throwable> T execute(RetryCallback<T, E> var1, RecoveryCallback<T> var2) throws E;
<T, E extends Throwable> T execute(RetryCallback<T, E> var1, RetryState var2) throws E, ExhaustedRetryException;
<T, E extends Throwable> T execute(RetryCallback<T, E> var1, RecoveryCallback<T> var2, RetryState var3) throws E;
}
使用示例
java
// 定义RetryTemplate, 重试2次, 每次间隔100毫秒
@Configuration
public class RetryConfiguration {
@Bean
public RetryTemplate retryTemplate() {
RetryTemplate retryTemplate = new RetryTemplate();
FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
fixedBackOffPolicy.setBackOffPeriod(100l);
retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
retryPolicy.setMaxAttempts(2);
retryTemplate.setRetryPolicy(retryPolicy);
return retryTemplate;
}
}
// 测试
@Autowired
private RetryTemplate retryTemplate;
@Test
public void testRetryTemplate() {
retryTemplate.execute(retryContext -> {
errorService.throwRunEx("newBee2");
return null;
});
}
// 执行结果
throwRunEx executed, arg: newBee2, time: 1686460287112
throwRunEx executed, arg: newBee2, time: 1686460287226
java.lang.RuntimeException: this is a test runtime exception!
Listeners
- 重试过程提供了监听机制, 可拓展监听器来实现更多功能, 如以下案例增加了日志打印
java
@Slf4j
public class DefaultListenerSupport extends RetryListenerSupport {
@Override
public <T, E extends Throwable> void close(RetryContext context,
RetryCallback<T, E> callback, Throwable throwable) {
log.info("onClose");
super.close(context, callback, throwable);
}
@Override
public <T, E extends Throwable> void onError(RetryContext context,
RetryCallback<T, E> callback, Throwable throwable) {
log.info("onError");
super.onError(context, callback, throwable);
}
@Override
public <T, E extends Throwable> boolean open(RetryContext context,
RetryCallback<T, E> callback) {
log.info("onOpen");
return super.open(context, callback);
}
}
java
// 需要注册
retryTemplate.registerListener(new DefaultListenerSupport());
// 执行结果
2023-06-11 13:17:58.228 INFO 15460 --- [ main] c.p.l.d.service.DefaultListenerSupport : onOpen
throwRunEx executed, arg: newBee2, time: 1686460678228
2023-06-11 13:17:58.228 INFO 15460 --- [ main] c.p.l.d.service.DefaultListenerSupport : onError
throwRunEx executed, arg: newBee2, time: 1686460678342
2023-06-11 13:17:58.342 INFO 15460 --- [ main] c.p.l.d.service.DefaultListenerSupport : onError
2023-06-11 13:17:58.342 INFO 15460 --- [ main] c.p.l.d.service.DefaultListenerSupport : onClose
java.lang.RuntimeException: this is a test runtime exception!