分别可以采用guava-retry和spring-retry两两种方式
一、guava-retry方式
1、引入依赖
<dependency>
<groupId>com.github.rholder</groupId>
<artifactId>guava-retrying</artifactId>
<version>2.0.0</version>
</dependency>
2、自定义监听器,重试时触发
package com.llg.retry;
import com.github.rholder.retry.Attempt;
import com.github.rholder.retry.RetryListener;
public class MyRetryListener implements RetryListener {
@Override
public <V> void onRetry(Attempt<V> attempt) {
if(attempt.hasException()){
//有异常
System.out.println("异常:" + attempt.getExceptionCause().toString());
}else{
//正常
System.out.println("没问题");
}
}
}
3、配置重试器,主要设置重试次数和频率,重试监听器等;使用重试机制,代码如下
package com.llg.retry;
import com.github.rholder.retry.*;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@SpringBootApplication
@RestController
public class RetryApplication {
public static void main(String[] args) {
SpringApplication.run(RetryApplication.class, args);
}
private static final Retryer retryer = RetryerBuilder.newBuilder()
.retryIfException()//异常时重试
.withWaitStrategy(WaitStrategies.fixedWait(5, TimeUnit.SECONDS))//每隔5秒重试一次
.withStopStrategy(StopStrategies.stopAfterAttempt(3))//重试3次后停止重试
.withRetryListener(new MyRetryListener())//重试时触发自定义监听器(首次调用方法时也会调用)
.build();
@GetMapping("/testRetry")
public String testRetry(){
try {
retryer.call(() -> {
System.out.println(1/0);
return false;
});
} catch (Exception e) {
e.printStackTrace();
}
return "hello";
}
}
4、测试,启动程序,访问接口http://localhost:8080/testRetry,可以看到重试了三次后程序抛出异常
二、spring-retry方式
1、引入依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.1</version>
</dependency>
2、启动类加上注解 @EnableRetry
@SpringBootApplication
@EnableRetry
public class RetryApplication {
...
}
3、在service层需要重复执行的方法上加上注解 @Retryable,并配置重试机制;标记@Recover的方法会在重试次数达到配置的最大次数时调用。
package com.llg.retry;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
@Service
public class RetryService {
@Retryable(
value = {Exception.class},
maxAttempts = 3,
backoff = @Backoff(delay = 2000L,multiplier = 2)
)
public void doSomething(String param){
System.out.println("do something...");
System.out.println(1/0);
}
@Recover
public void recover(Exception e,String param) {
System.out.println("达到最大重试次数,或抛出了一个没有指定进行重试的异常:" + e.getMessage());
}
}
4、编写controller,调用service方法
package com.llg.retry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SpringRetryTestController {
@Autowired
RetryService retryService;
@GetMapping("springRetry")
public String testRetry(){
retryService.doSomething("1111");
return "hello retry";
}
}
5、测试,访问http://localhost:8080/springRetry
6、注意事项
- recover方法不能有返回值,否则不会调用
- retryable方法不能被本类方法调用,否则无效
三、总结
1、spring-retry 和 guava-retry 工具都是线程安全的重试,能够支持并发业务场景的重试逻辑正确性
2、spring-retry使用很方便,只需加上相应注解,很符合springboot的习惯
3、guava-retry的配置更加灵活多样,spring-retry只能通过抛出异常的方式重试