在实际应用过程中,我们时常会遇到需要重试的机制。例如发送短信的时候,发送失败一次后需要再次发起第二次或者第三次重试,常规的思路就是记录当前短信对应的发送失败次数,当小于三次且均为失败时就发起请求。这里我们介绍一种极为方便的重试机制,springboot下整合retry。

一. 使用场景

发送短信请求,若失败则需要再次发起请求,若一直失败则需要满足达到了两次重试请求。

若不引入任何重试机制,我们的实现逻辑大体如下,记录短信唯一标识以及对应的请求历史和请求结果,若失败则累加失败次数,直到某一次成功了,或者重试次数达到了三次。

这里我们需要引入数据库来记录失败次数,以及增加数据库请求,有没有一种更方便的方式来实现呢,答案是有的。

二. Retry机制

这里我们以SpringBoot为例:

  • 首先我们引入相关pom依赖

    <dependencies>
        <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
             <groupId>org.springframework.retry</groupId>
             <artifactId>spring-retry</artifactId>
         </dependency>
         <dependency>
              <groupId>org.aspectj</groupId>
              <artifactId>aspectjweaver</artifactId>
         </dependency>
    </dependencies>
    
  • 在启动类上加上注解@EnableRetry

    @SpringBootApplication
    @EnableRetry
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class,args);
        }
    }
    
  • 定义Controller层:这里我们把下层异常进行throws抛出,或者我们进行try,catch;否则重试机制将会不生效。

    @RestController
    public class HelloController {
    
        Logger logger = LoggerFactory.getLogger(getClass());
    
        @Autowired
        private SmsService smsService;
    
        @GetMapping("/sendSms")
        public void sendSms(@RequestParam String phoneNumber, @RequestParam String content) throws Exception{
            boolean isSuccess = smsService.sendSms(phoneNumber, content);
            if(isSuccess){
            	logger.info("短信发送成功");
            }else{
                logger.error("短信发送失败");
            }
    
        }
    
    }
    
  • 定义Service

    @Service
    public class SmsService {
    
        private Logger logger = LoggerFactory.getLogger(getClass());
    
    
        @Retryable(value = Exception.class,maxAttempts = 3,backoff = @Backoff(delay = 2000,multiplier = 1.5))
        public boolean sendSms(String phoneNumber, String content) throws Exception{
            // 模拟短信发送失败
            throw new Exception("短信发送失败");
        }
    }
    
  • 解释@Retryable注解

    value:表示遇到何种异常情况下需要重试

    maxAttempts:表示最大重试次数

    delay:表示重试的延迟时间(毫秒计数)

    multiplier:表示上一次延迟时间为本次的倍数

以上就是我们实现的简单重试机制示例,相较于记录失败次数并发起重试,这种方式是不是简单又优雅,第一次看到这种实现方法的时候笔者也被惊艳到了,若在实际业务开发过程中需要使用重试机制,我们可以借鉴该种实现思路。

三. 拓展

若在@Retryable设置的最大重试次数下,还是没有成功,我们需要回调另一个方法,那我们该如何实现。

这里我们引入@Recover注解。

我们在sendSms的Service类中,加上以下代码:

@Recover
public void recover(Exception e){
        logger.warn("发送短信失败!!!");
        //记日志到数据库
}

我们再进行测试,就会发现,当我们达到最大重试3次后,若还是失败则会执行该代码块。

参考资料:

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐