【问题标题】:How implement a retry mechanism for restTemplate如何实现restTemplate的重试机制
【发布时间】:2019-10-22 17:37:22
【问题描述】:

我已经实现了一个通过 Resttemplate 调用外部服务的 java 方法。同样,我还在该方法中实现了一些额外的业务逻辑。我如何为这些休息调用实现重试机制。还需要考虑以下几点。

  1. 我无法为整个方法添加重试。
  2. 最好为 rest 调用添加重试(通过 resttemplate)。
  3. 应该有一种方法可以为不需要的休息呼叫禁用重试选项。

【问题讨论】:

  • 我认为你可以做这样的事情。从 0 到 9 循环并拨打电话。如果你成功了,那么打破一个循环并继续执行结果,否则迭代它。如果它在 10 次调用中没有返回任何东西,那么你为什么要调用该方法并浪费你的时间。
  • 这不是一个好方法。我已经实现了这些方法。我需要通过最小化对当前实现的修改来做到这一点。如果我们使用通用配置为resttemplate添加这个重试,那么我可能不需要修改当前的实现

标签: java spring spring-boot spring-mvc


【解决方案1】:

您可以在HttpClient 中添加重试机制并将其用于RestTemplate,如下所示:

@Bean
public ClientHttpRequestFactory clientFactory() {
    HttpClient httpClient = HttpClients.custom()            
        .setRetryHandler((exception, executionCount, context) -> {
            if (executionCount > 3) {
                log.warn("Maximum retries {} reached", 3);
                return false;
            }
            if (<some condition for retry>) {
                log.warn("Retry {}", executionCount);
                return true;
            }
            return false;
        })
        .build();

    return new HttpComponentsClientHttpRequestFactory(httpClient);
}
@Bean
public RestTemplate customRestTemplate(@Qualifier("clientFactory") ClientHttpRequestFactory clientFactory){ 
    return new RestTemplate(clientFactory);
}

【讨论】:

  • 请注意,此解决方案仅适用于低级别网络故障。它不会重试 http 状态!= 2xx,例如 502。
  • @AnnevanderBom 您是否找到适用于自定义 HTTP 状态的解决方案?
【解决方案2】:

Spring 提供了带有 @Retry 注释的重试机制。您必须使用以下依赖项。

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>1.1.5.RELEASE</version>
</dependency>

Spring 提供了以下注解。

Spring 重试注解

@EnableRetry – 在 Spring Boot 项目中启用 Spring 重试

@Retryable – 表示任何方法都可以重试

@Recover – 指定回退方法

我在下面提供了示例代码。

@Configuration
@EnableRetry
@SpringBootApplication
public class MyApplication {
}

您可以参考完整的示例以了解更多信息。

【讨论】:

  • 这个注解应该添加到方法级别。对于我的场景,我不能这样做。如果我们从一次休息调用中得到错误,那么整个方法将再次执行。
  • 如果需要,可以将方法拆分为小的内聚函数/方法,然后添加注释。
  • 此注释的限制很少。特别是不能添加到相同的类方法和私有方法中。
  • 是的,有一些限制,但它抽象了很多东西,使其更容易实现。
  • 如果您正在使用 Spring-boot,您只需包含启动器 spring-boot-starter-batch 即可获得与 spring-boot 版本对齐的版本的依赖关系。