尝试使用@Retryable排除exception – 导致抛出ExhaustedRetryException

我正在尝试在调用REST模板的方法上使用@Retryable 。 如果由于通信错误而返回错误,我想重试,否则我想在调用时抛出exception。

当ApiException发生时,我得到一个ExhaustedRetryException,并且没有找到足够的’recoverables’,即@Recover方法,而不是被@Retryable抛出和忽略。

我以为我会看到如果只有可恢复的方法存在可能使它快乐并仍然按照希望执行。 没那么多。 它不是抛出exception,而是调用可恢复的方法。

 @Retryable(exclude = ApiException include = ConnectionException, maxAttempts = 5, backoff = @Backoff(multiplier = 2.5d, maxDelay = 1000000L, delay = 150000L)) Object call(String domainUri, ParameterizedTypeReference type, Optional domain = Optional.empty(), HttpMethod httpMethod = HttpMethod.POST) throws RestClientException { RequestEntity request = apiRequestFactory.createRequest(domainUri, domain, httpMethod) log.info "************************** Request Entity **************************" log.info "${request.toString()}" ResponseEntity response try { response = restTemplate.exchange(request, type) log.info "************************** Response Entity **************************" log.info "${response.toString()}" } catch (HttpStatusCodeException | HttpMessageNotWritableException httpException) { String errorMessage String exceptionClass = httpException.class.name.concat("-") if(httpException instanceof HttpStatusCodeException) { log.info "************************** API Error **************************" log.error("API responded with errors: ${httpException.responseBodyAsString}") ApiError apiError = buildErrorResponse(httpException.responseBodyAsString) errorMessage = extractErrorMessage(apiError) if(isHttpCommunicationError(httpException.getStatusCode().value())) { throw new ConnectionException(exceptionClass.concat(errorMessage)) } } errorMessage = StringUtils.isBlank(errorMessage) ? exceptionClass.concat(httpException.message) : exceptionClass.concat(errorMessage) throw new ApiException(httpMethod, domainUri, errorMessage) } if (type.type == ResponseEntity) { response } else response.body } @Recover Object connectionException(ConnectionException connEx) { log.error("Retry failure - communicaiton error") throw new ConnectionException(connEx.class.name + " - " + connEx.message) } 

任何见解将不胜感激。 这是错误还是操作员错误? 这是使用Spring Boot 1.3.6和Spring-Retry 1.1.3。

您的包含/排除语法看起来很糟糕 – 甚至不会编译。

我刚刚写了一个快速测试,如果你没有@Recover方法,它的工作原理与预期完全相同……

 package com.example; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.retry.annotation.EnableRetry; import org.springframework.retry.annotation.Retryable; @SpringBootApplication @EnableRetry public class So38601998Application { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(So38601998Application.class, args); Foo bean = context.getBean(Foo.class); try { bean.out("foo"); } catch (Exception e) { System.out.println(e); } try { bean.out("bar"); } catch (Exception e) { System.out.println(e); } } @Bean public Foo foo() { return new Foo(); } public static class Foo { @Retryable(include = IllegalArgumentException.class, exclude = IllegalStateException.class, maxAttempts = 5) public void out(String foo) { System.out.println(foo); if (foo.equals("foo")) { throw new IllegalArgumentException(); } else { throw new IllegalStateException(); } } } } 

结果:

 foo foo foo foo foo java.lang.IllegalArgumentException bar java.lang.IllegalStateException 

如果你只是添加

 @Recover public void connectionException(IllegalArgumentException e) { System.out.println("Retry failure"); } 

你得到

 foo foo foo foo foo Retry failure bar org.springframework.retry.ExhaustedRetryException: Cannot locate recovery method; nested exception is java.lang.IllegalStateException 

所以你需要一个全能的@Recover方法……

 @Recover public void connectionException(Exception e) throws Exception { System.out.println("Retry failure"); throw e; } 

结果:

 foo foo foo foo foo Retry failure bar Retry failure java.lang.IllegalStateException