前提
这篇博文是这套Spring学习笔记的第十篇——Spring Retry篇,主要内容包括Spring MVC的基础知识和应用。如果需要了解有关Spring的综述信息或博文的索引信息,请移步:
《综述篇》
从问题出发
大家都知道,Java中有一大类异常叫RuntimeException
,运行时异常。可能造成这类这类异常的代码可以通过编译器的语法检查,在运行的过程中可能会因为网络抖动、内存溢出等问题触发异常。
而我的问题就发生在了网络抖动上。我的工程包含邮件服务,一般情况下可以正常运转。但是每个月总有那么一两次,可能因为网络抖动的原因,程序就会出现邮件服务器连接超时的异常。原本该定时发出去的邮件,就得手动来发了。
之前看到过有关 Spring Retry的文章,但是存在侥幸心理就没有学习。随着用户的增多,每天要发送的邮件也多了起来,这样如果遇到异常,手动发送那么多邮件也会特别累。那么就到了必须学习它的时候了。
Spring Retry
Spring Retry是隶属于Spring家族的重试框架,它不在Spring的核心包中,需要额外引入。
就上述的几种Runtime Exception
,内存溢出这类的异常是不适合用它来解决的,因为你的异常可能是因为逻辑异常造成的,错了就是错了,重试多少次结果都一样。但是网络抖动这类的异常不同,只要代码逻辑无误,除非对面的服务器彻底奔溃了,我重试一遍、两遍连不上,重试十遍、二十遍总是能连上的。
开始实现
首先从Maven中央仓库找到POM信息:
<!-- https://mvnrepository.com/artifact/org.springframework.retry/spring-retry -->
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.2.2.RELEASE</version>
</dependency>
加入到pom.xml
文件的<dependencies>
标签中。
接下来看代码,我的代码中会触发连接超时异常的代码就是这几行:
public Session getSession(Properties properties) {
return Session.getInstance(properties);
}
在获取会话的过程中,因为网络波动,就会出现连接超时的情况。
实现Retry需要以下的几个步骤:
①给函数所在的类冠上@EnableRetry
注解,启用重试
@EnableRetry(proxyTargetClass = true)
在前面的博文中我们说过,proxyTargetClass设置为false
时使用基于接口的代理,设置为true
时,使用基于类的代理(需要引用cglib
包)。
②给需要重试的函数冠上@Retryable
注解
@Retryable(value = MailConnectException.class, maxAttempts = 60, backoff = @Backoff)
其中:
1)value
指示的是目标异常,即遇到该异常就重试;
2)maxAttempts
表示最大尝试次数;
3)backoff
表示退避算法,默认使用@Backoff
注解,即延时1000ms进行下一次重试。
③添加兜底方法
兜底方法即达到最大重试次数仍失败后的处理方法,他需要:
1)被冠以@Recover
注解;
2)使用上述被重试的函数指定的异常作为入参,如上述的MailConnectException
邮件连接异常。
@Recover
public Session recover(MailConnectException mce, Properties properties) {
logger.error("Mail Connection Still Failing After 60 Times of Attempts.", mce);
return null;
}
注意:想要正确地触发
recover
函数,需要具备以下条件:
①返回值必须和被重试的函数返回值一致,如这里的Session
;
②参数中除了第一个是触发的异常外,后面的参数需要和被重试函数的参数列表一致,如这里的参数只有一个properties: Properties
;
③当然这里的返回值部分也可以再做一次手动重试,但是已经尝试那么多次都失败了,所以在兜底函数中再做一次也意义不大。因此我的考虑是,这里就用来做日志记录就好。
后记
Retry虽然不能完全解决网络抖动的问题,但是可以大幅的提高工程的鲁棒性,相信除非对面的服务器彻底崩溃了,或者网络彻底中断了,重试个60次应该有很大的概率可以成功连接。