SpringBoot - 网络请求模版类RestTemplate使用详解8(自动重试机制)

作者: hangge 发布时间: 2019-11-26 浏览: 2855 次 编辑

本文是对前一篇文章关于请求异常处理(点击查看)的补充。有时当我们调用一个接口可能由于网络等原因造成第一次请求失败,如果再去尝试可能就成功了,这就是重试机制。下面演示如何结合 Spring Retry 实现请求发生异常时自动进行重试(重新发起请求)。

十一、请求异常自动重试

1,安装配置

(1)编辑项目 pom.xml 文件,添加 Spring Retry 相关依赖。

<!-- 重试机制 -->
<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>1.1.2.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>

(2)在主类上加入 @EnableRetry 注解,启用重试功能。

@SpringBootApplication
@EnableRetry
public class DemoApplication {
 
    public static void main(String[] args) {
        ConfigurableApplicationContext context
                = SpringApplication.run(DemoApplication.class, args);
    }
}

2,使用样例

(1)由于这是前一篇文章关于请求异常处理的补充,首先我同样要创建一个自己的异常处理控制器(RestThrowErrorHandler)并在 RestTemplate 配置类中进行配置。目的是让 4XX5XX 这样的请求也能成功返回到客户端。具体代码参考之前的文章:


(2)首先修改前文的 Service 类,在需要重试的方法上添加 @Retryable @Backoff 注解,使其在发生异常时能够自动重试。

(1)@Retryable 注解的方法在发生异常时会重试,参数说明:

  • value:当指定异常发生时会进行重试
  • include:和 value 一样,默认空。如果 exclude 也为空时,所有异常都重试
  • exclude:指定异常不重试,默认空。如果 include 也为空时,所有异常都重试
  • maxAttemps:最大重试次数,默认 3
  • backoff:重试等待策略,默认没有

(2)@Backoff 注解为重试等待策略,参数说明:

  • delay:指定重试的延时时间,默认为 1000L
  • multiplier:指定延迟的倍数,默认为 0。比如 delay=5000l,multiplier=2 时,第一次重试为 5 秒后,第二次为 10 秒,第三次为 20 秒。
@Service
public class UserService {
 
    @Autowired
    private RestTemplate restTemplate;
 
    @Retryable(value = RestClientException.class, maxAttempts = 3,
            backoff = @Backoff(delay = 5000l,multiplier = 1))
    public String getInfo() {
        String url = "http://localhost:8080/xxxxxx";
        ResponseEntity responseEntity = restTemplate.getForEntity(url, String.class);
        // 判断请求是否发生异常
        if(!responseEntity.getStatusCode().is2xxSuccessful()){
            System.out.println("请求失败...");
            // 抛出异常
            throw new RestClientException(responseEntity.getBody());
        }
        // 没有异常的话则返回正常的响应结果
        return responseEntity.getBody();
    }
}


(2)然后 Contoller 会调用这个 Service,这边代码同前文一样:

注意:由于 retry 用到了 aspect 增强,所以会有 aspect 的坑,就是方法内部调用,会使 aspect 增强失效,那么 retry 当然也会失效。

  • 比如这里重试方法是定义在 Service 类里面,Controller 调用 Service 的这个方法,重试机制是没问题的。
  • 但如果重试方法直接定义在这个 Controller 里面,也就同一个类里面内部调用,那么重试机制就会失效。
@RestController
public class HelloController {
 
    @Autowired
    private UserService userService;
 
    @GetMapping("/test")
    public String test() {
        return userService.getInfo();
    }
}


(3)全局的异常处理类和前文一样,当超过重试次数是异常会被抛出,这个全局的异常处理类会捕获这个异常,并返回给前端处理的结果。

@ControllerAdvice
public class CustomExceptionHandler {
    @ExceptionHandler(RestClientException.class)
    public ResponseEntity throwRestException(RestClientException restClientException){
        return new ResponseEntity(restClientException.getMessage(),
                HttpStatus.BAD_REQUEST);
    }
}

(4)测试一下,由于我们使用 RestTemplate 请求一个不存在的接口,可以看到 UserService 方法重复执行3次(每次间隔5秒)。

原文:SpringBoot - 网络请求模版类RestTemplate使用详解8(自动重试机制)


(5)超过重试次数后异常信息才返回到前端页面。

原文:SpringBoot - 网络请求模版类RestTemplate使用详解8(自动重试机制)

附:同时指定多个异常

@Retryable 注解的 value 属性可以同时设置多个异常类型,只要其中某个异常发生时,被注解的方法就会进行重试。

@Service
public class UserService {
 
    @Autowired
    RestTemplate restTemplate;
 
    @Retryable(value = {RestClientException.class, ConnectException.class}, maxAttempts = 3,
            backoff = @Backoff(delay = 5000l,multiplier = 1))
    public String getInfo() {
        String url = "http://localhost:8080/xxxxxx";
        ResponseEntity responseEntity = restTemplate.getForEntity(url, String.class);
        // 判断请求是否发生异常
        if(!responseEntity.getStatusCode().is2xxSuccessful()){
            System.out.println("请求失败...");
            // 抛出异常
            throw new RestClientException(responseEntity.getBody());
        }
        // 没有异常的话则返回正常的响应结果
        return responseEntity.getBody();
    }
}



原文出自:www.hangge.com 转载请保留原文链接:https://www.hangge.com/blog/cache/detail_2522.html