spring的@Retryable重试机制

前言

在很多业务场景中,我们需要用重试机制。比如说在微服务中,服务之间的调用有时候会因为网络波动导致调用失败,这时候代码中进行失败重试就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。

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱琴孩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值