一般从事软件开发工作的同时通常需要调用远程服务,但是即使是亚马逊、阿里巴巴、腾讯这些巨头提供的服务也可能因为网络或者服务高可用方面的一些问题,或许会遇到超时等异常情况,这时候我们就必需要考虑到异常情况下我们的应用如何能处变不惊处理这些异常,是直接抛出异常还是说可以自动进行一些处理呢? 通常情况下我们首先想到的解决方案一定是重试对吧。
我看过很多代码,他们都怎么写的呢,如下
public String invoke(int times) {
for(int i = 0; i < times; i ++) {
try{
// do some thing
// return
}catch(Exception e) {
return invoke(i);
}
}
}
上面的代码意思是首先传入一个次数参数,假设我们传递的是3,那么当遇到异常的时候,重新调用当前方法,次数变为2…
你有没有发现如果调用外部服务很多的时候,这样的for循环写的让人不舒服,因为都是重复的代码,而且显的很啰嗦呢,spring boot给我们带来了一些福音,我们看看spring boot框架下如何进行重试
1、 首先引入JAR包
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
2、使用注解 @EnableRetry @Retryable 下面先给出代码,然后我们再讲注解的含义
@SpringBootApplication
@EnableRetry
public class LeaningNotesApplication {
public static void main(String[] args) {
SpringApplication.run(LeaningNotesApplication.class, args);
}
}
@Service
public class BookService {
private Random random = new Random();
@Retryable(include = RuntimeException.class, maxAttempts = 3)
public String readingList() {
int randomInt= random.nextInt(10) ;
if(randomInt < 8){ //模拟调用失败情况
System.out.println("调用失败发生异常");
throw new RuntimeException("call dependency service fail.");
}else{
System.out.println("调用成功");
return "调用成功 ;number:"+randomInt;
}
}
@Recover
public String reliable() {
return "Cloud Native Java (O'Reilly)";
}
}
3、我们再写一个接口,通过浏览器来访问这个接口,看看上面的代码帮我们进行了几次重试,另外如果重试了几次都失败,他又执行了什么方法
@RestController
public class BookController {
@Autowired
private BookService bookService;
@GetMapping("/book")
public String book() {
return bookService.readingList();
}
}
上面的这个代码就比较简单了,我们可以通过http://localhost:8080/book 来访问这个接口,然后在控制台看结果,我都迫不及待想要去试试了,你呢?
4、我打开了浏览器输入了地址,然后我看到控制台打印了下面这样的信息
调用失败发生异常
调用成功
是的,你没看错,先输出了一个异常日志,然后又输出了一个成功日志,说明了它在异常的情况下帮我重试了一次,然后才成功的,当然你也可以多尝试几次看看不一样的结果。
5、@Retryable 几个比较重要的参数
value : 抛出某些异常的时候才进行重试
include: 和value的含义类似
exclude: 排除某些异常不进行重试,这里要注意的是,如果value、include、exclude都为空的时候则任何异常都进行重试
maxAttempts: 最大重试次数
backoff: 重试策略,默认使用注解@Backoff 而@BackOff中value的默认为1000L,multiplier的默认值为0,表示默认情况下固定暂停1秒进行重试,如果我们把multiplier调整为2,那么表面第一次进行重试时间为1秒,第二次为2秒,第三次为4秒。
是不是很牛逼,有木有GET到新技能?
注意:注解了@Recover方法的参数可以没有,如果有一定是和注解@Retryable处理的异常是一样的或者是它的子集,否则recover方法将不能被执行,并不是网上一些人瞎逼逼说一定要和@Retryable处理的异常要保持一致