前言
在很多业务场景中,我们需要用重试机制。比如说在微服务中,服务之间的调用有时候会因为网络波动导致调用失败,这时候代码中进行失败重试就ok了,当然这种重试机制通常会和异步结合使用,否则因为重试导致响应时间变长,这肯定是不行的。至于异步,无论是spring自带的异步机制,还是整合消息中间件。具体异步方式这里不重点讲。当然我们也可以自己用代码逻辑实现重试,不过这种方式不统一,要写一些非业务代码,对代码的侵入比较严重。既然spring已经支持重试,我们就没必要自己重复造轮子了。
添加依赖
前面也说到,我们要使用spring自带的重试机制,所以需要在项目的依赖加上spring重试的依赖包。
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
测试demo
在引入依赖之后,我们需要在启动上加上@EnableRetry注解,开启重试机制。
/**
* @author 蒋墨风
* @title: SpringRetryController
* @projectName client1
* @description: springRetry测试
* @date 2019/10/19 8:47
*/
@RestController
@RequestMapping("/springRetry")
public class SpringRetryController {
private static final Logger LOG = LoggerFactory.getLogger(SpringRetryController.class);
@Autowired
private SpringRetryService pringRetryService;
@RequestMapping("/testSpringRetry")
public String testSpringRetry() {
LOG.info("invoke method testSpringRetry! ");
try {
pringRetryService.testRetry();
} catch (Exception e) {
LOG.error("重试失败了", e);
}
return " retry success";
}
}
下面就是重试代码
/**
* @author 蒋墨风
* @title: SpringRetryService
* @projectName client1
* @description: 测试SpringRetry
* @date 2019/10/19 8:51
*/
@Service
public class SpringRetryService {
private static final Logger LOGGER = LoggerFactory.getLogger(SpringRetryService.class);
@Retryable(value = {Exception.class}, maxAttempts = 3, backoff =@Backoff(value = 3000,
multiplier = 2))
public void testRetry() throws Exception {
boolean result = false;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
LOGGER.info("重试方法被调用,当前时间是" + sdf.format(new Date()));
int i = 9 / 0;
} catch (Exception e) {
throw new Exception("重试之后,还是失败了!", e);
}
}
@Recover
public void testRecovery(Exception e) {
LOGGER.warn("重试依旧失败了,这时候就需要发送短信报警啦!");
}
}
测试效果如下
注意点
1.由于aspect机制,不要在同一个类中调用加上@Retryable注解的方法,会使aspect增强失效,那么retry当然也会失效。比如下面这种方式
public class demo {
public void A() {
B();
}
@Retryable(Exception.class)
public void B() {
throw new RuntimeException("retry...");
}
}
2.在实际项目中,如果是为了避免网络波动而加上的重试机制,在重试的时候需要加上延迟,也就是后面的重试时间间隔设置大一点,这样效果可能好一点,否则你每隔1秒重试一次,这样的重试很多都是徒劳的。上面的代码第一次重试是延迟3秒,第二次6秒,multiplier 设置了延迟翻倍。
3.@Recover注解是假如经过重试之后,还是调用失败了,这时候就需要发短信报警了,开发,运维就要忙起来了。我们可以根据自己的业务场景来发送短信或者邮件通知相关开发和运维。当然你也可以简单记录下日志,不做其他操作。
4.@Recover生效的前提是在@Retryable注解的方法和@Recover注解的方法的返回值保持一致。否则会在报错日志中看到这句话org.springframework.retry.ExhaustedRetryException: Cannot locate recovery method。