@Recover 方法不会被@Retryable 触发
@Recover methods are not triggered with @Retryable
在 @Retryable
函数上获得 ExhaustedRetryException
后,我遵循了这个 。 @Retryable
函数正在重试。
这是具有 @Retryable
功能的委托:
@Component
public class OrderRequestDelegate {
private static final Logger LOGGER = LoggerFactory.getLogger(OrderRequestDelegate.class);
private final OrderRequestDao orderRequestDao;
private final SqsQueueDao sqsQueueDao;
@Autowired
public OrderRequestDelegate(OrderRequestDao orderRequestDao, SqsQueueDao sqsQueueDao) {
this.orderRequestDao = orderRequestDao;
this.sqsQueueDao = sqsQueueDao;
}
@Retryable(include=NoResultException.class, backoff = @Backoff(delay = 100, maxDelay = 101), maxAttempts = 5)
public OrderRequest processItem(String storeId, String message) {
Long id = 999L;
OrderRequest result = orderRequestDao.findOne(id);
if (result == null) {
LOGGER.info("Tried in retryable");
throw new NoResultException();
}
return result;
}
@Recover
public void recover(NoResultException e, Long id) {
LOGGER.info("recover triggered");
}
@Recover
public void recover(Exception e, Long id) throws Exception {
LOGGER.info("retry failure");
}
}
这是函数调用者的 class:
@RestController
@RequestMapping("/orderRequests")
@Api(description = "orders API")
public class OrderRequestController {
private static final Logger LOGGER = LoggerFactory.getLogger(OrderRequestController.class);
private final OrderRequestDelegate orderRequestDelegate;
@Autowired
public OrderRequestController(OrderRequestDelegate orderRequestDelegate) {
this.orderRequestDelegate = orderRequestDelegate;
}
//...
@ApiOperation(value="test function")
@RequestMapping(method = RequestMethod.GET)
public String get() {
orderRequestDelegate.processItem("100", "abc");
return String.format("Worked");
}
}
以及包含 @EnableRetry
注释的应用程序 class:
@SpringBootApplication
@EnableRetry
public class FulfillmentApplication extends SpringBootServletInitializer {
private static final Logger LOGGER = LoggerFactory.getLogger(FulfillmentApplication.class);
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(FulfillmentApplication.class);
}
public static void main(String[] args) {
LOGGER.debug("Starting Spring application main...");
SpringApplication.run(FulfillmentApplication.class, args);
}
}
这是我 运行 @Retryable
函数时的堆栈跟踪:
2017-01-27 12:58:21.918 INFO 93294 --- [nio-8080-exec-1] c.c.f.delegate.OrderRequestDelegate : Tried in retryable
2017-01-27 12:58:22.022 INFO 93294 --- [nio-8080-exec-1] c.c.f.delegate.OrderRequestDelegate : Tried in retryable
2017-01-27 12:58:22.129 INFO 93294 --- [nio-8080-exec-1] c.c.f.delegate.OrderRequestDelegate : Tried in retryable
2017-01-27 12:58:22.231 INFO 93294 --- [nio-8080-exec-1] c.c.f.delegate.OrderRequestDelegate : Tried in retryable
2017-01-27 12:58:22.336 INFO 93294 --- [nio-8080-exec-1] c.c.f.delegate.OrderRequestDelegate : Tried in retryable
2017-01-27 12:58:22.352 ERROR 93294 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.retry.ExhaustedRetryException: Cannot locate recovery method; nested exception is javax.persistence.NoResultException] with root cause
javax.persistence.NoResultException: null
at com.cfa.fulfillmentApi.delegate.OrderRequestDelegate.processItem(OrderRequestDelegate.java:44) ~[classes/:na]
at com.cfa.fulfillmentApi.delegate.OrderRequestDelegate$$FastClassBySpringCGLIB$$f297a63a.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.retry.interceptor.RetryOperationsInterceptor.doWithRetry(RetryOperationsInterceptor.java:74) ~[spring-retry-1.1.2.RELEASE.jar:na]
at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:263) ~[spring-retry-1.1.2.RELEASE.jar:na]
at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:168) ~[spring-retry-1.1.2.RELEASE.jar:na]
at org.springframework.retry.interceptor.RetryOperationsInterceptor.invoke(RetryOperationsInterceptor.java:98) ~[spring-retry-1.1.2.RELEASE.jar:na]
at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.invoke(AnnotationAwareRetryOperationsInterceptor.java:118) ~[spring-retry-1.1.2.RELEASE.jar:na]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at com.cfa.fulfillmentApi.delegate.OrderRequestDelegate$$EnhancerBySpringCGLIB$ec8aa9.processItem(<generated>) ~[classes/:na]
at com.cfa.fulfillmentApi.controller.OrderRequestController.get(OrderRequestController.java:45) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_112]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_112]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_112]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_112]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:220) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55) ~[spring-boot-1.4.3.RELEASE.jar:1.4.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:105) ~[spring-boot-actuator-1.4.3.RELEASE.jar:1.4.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:89) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:106) ~[spring-boot-actuator-1.4.3.RELEASE.jar:1.4.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:108) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:784) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:802) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1410) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.6.jar:8.5.6]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_112]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_112]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.6.jar:8.5.6]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_112]
这是该答案中的完整应用程序,已修改为与您的应用程序功能相同;如果您仍然无法找出问题所在,请使用完整配置和调试日志编辑您的问题。
@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");
System.out.println("Recovered");
}
catch (Exception e) {
System.out.println("Not recovered: " + e);
}
try {
bean.out("bar");
}
catch (Exception e) {
System.out.println("Not recovered: " + e);
}
}
@Component
public static class Foo {
@Retryable(include=NoResultException.class, backoff = @Backoff(delay = 100, maxDelay = 101), maxAttempts = 5)
public void out(String foo) {
System.out.println(foo);
if (foo.equals("foo")) {
throw new NoResultException();
}
else {
throw new IllegalStateException();
}
}
@Recover
public void connectionException(NoResultException e) {
System.out.println("Retry failure");
}
@Recover
public void connectionException(Exception e) throws Exception {
System.out.println("Retry failure");
throw e;
}
}
}
结果(使用 o.s.retry
的 DEBUG 日志记录)
14:16:25.803 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=0
foo
14:16:25.913 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=1
14:16:25.914 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=1
foo
14:16:26.017 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=2
14:16:26.017 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=2
foo
14:16:26.121 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=3
14:16:26.121 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=3
foo
14:16:26.223 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=4
14:16:26.223 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=4
foo
14:16:26.224 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=5
14:16:26.224 [main] DEBUG o.s.retry.support.RetryTemplate - Retry failed last attempt: count=5
Retry failure
Recovered
14:16:26.224 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=0
bar
14:16:26.225 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=1
14:16:26.225 [main] DEBUG o.s.retry.support.RetryTemplate - Retry failed last attempt: count=1
Retry failure
Not recovered: java.lang.IllegalStateException
看来你和我一样只是错过了基础部分。
用@Recover注解的方法应该采用相同类型的参数(以及可选的Throwable或其子类类型参数)。除此之外 return 类型也应该相同。
下面是您的恢复方法在重试耗尽后应该如何被触发。
@Component
public static class Foo {
@Retryable(include=NoResultException.class, backoff = `@Backoff(delay = 100, maxDelay = 101), maxAttempts = 5)`
public void out(String foo) {
System.out.println(foo);
if (foo.equals("foo")) {
throw new NoResultException();
}
else {
throw new IllegalStateException();
}
}
@Recover
public void connectionException(NoResultException e, String foo) {
System.out.println("Retry failure");
}
@Recover
public void connectionException(Exception e, String foo) throws Exception {
System.out.println("Retry failure");
throw e;
}
}
在 @Retryable
函数上获得 ExhaustedRetryException
后,我遵循了这个 @Retryable
函数正在重试。
这是具有 @Retryable
功能的委托:
@Component
public class OrderRequestDelegate {
private static final Logger LOGGER = LoggerFactory.getLogger(OrderRequestDelegate.class);
private final OrderRequestDao orderRequestDao;
private final SqsQueueDao sqsQueueDao;
@Autowired
public OrderRequestDelegate(OrderRequestDao orderRequestDao, SqsQueueDao sqsQueueDao) {
this.orderRequestDao = orderRequestDao;
this.sqsQueueDao = sqsQueueDao;
}
@Retryable(include=NoResultException.class, backoff = @Backoff(delay = 100, maxDelay = 101), maxAttempts = 5)
public OrderRequest processItem(String storeId, String message) {
Long id = 999L;
OrderRequest result = orderRequestDao.findOne(id);
if (result == null) {
LOGGER.info("Tried in retryable");
throw new NoResultException();
}
return result;
}
@Recover
public void recover(NoResultException e, Long id) {
LOGGER.info("recover triggered");
}
@Recover
public void recover(Exception e, Long id) throws Exception {
LOGGER.info("retry failure");
}
}
这是函数调用者的 class:
@RestController
@RequestMapping("/orderRequests")
@Api(description = "orders API")
public class OrderRequestController {
private static final Logger LOGGER = LoggerFactory.getLogger(OrderRequestController.class);
private final OrderRequestDelegate orderRequestDelegate;
@Autowired
public OrderRequestController(OrderRequestDelegate orderRequestDelegate) {
this.orderRequestDelegate = orderRequestDelegate;
}
//...
@ApiOperation(value="test function")
@RequestMapping(method = RequestMethod.GET)
public String get() {
orderRequestDelegate.processItem("100", "abc");
return String.format("Worked");
}
}
以及包含 @EnableRetry
注释的应用程序 class:
@SpringBootApplication
@EnableRetry
public class FulfillmentApplication extends SpringBootServletInitializer {
private static final Logger LOGGER = LoggerFactory.getLogger(FulfillmentApplication.class);
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(FulfillmentApplication.class);
}
public static void main(String[] args) {
LOGGER.debug("Starting Spring application main...");
SpringApplication.run(FulfillmentApplication.class, args);
}
}
这是我 运行 @Retryable
函数时的堆栈跟踪:
2017-01-27 12:58:21.918 INFO 93294 --- [nio-8080-exec-1] c.c.f.delegate.OrderRequestDelegate : Tried in retryable
2017-01-27 12:58:22.022 INFO 93294 --- [nio-8080-exec-1] c.c.f.delegate.OrderRequestDelegate : Tried in retryable
2017-01-27 12:58:22.129 INFO 93294 --- [nio-8080-exec-1] c.c.f.delegate.OrderRequestDelegate : Tried in retryable
2017-01-27 12:58:22.231 INFO 93294 --- [nio-8080-exec-1] c.c.f.delegate.OrderRequestDelegate : Tried in retryable
2017-01-27 12:58:22.336 INFO 93294 --- [nio-8080-exec-1] c.c.f.delegate.OrderRequestDelegate : Tried in retryable
2017-01-27 12:58:22.352 ERROR 93294 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.retry.ExhaustedRetryException: Cannot locate recovery method; nested exception is javax.persistence.NoResultException] with root cause
javax.persistence.NoResultException: null
at com.cfa.fulfillmentApi.delegate.OrderRequestDelegate.processItem(OrderRequestDelegate.java:44) ~[classes/:na]
at com.cfa.fulfillmentApi.delegate.OrderRequestDelegate$$FastClassBySpringCGLIB$$f297a63a.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.retry.interceptor.RetryOperationsInterceptor.doWithRetry(RetryOperationsInterceptor.java:74) ~[spring-retry-1.1.2.RELEASE.jar:na]
at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:263) ~[spring-retry-1.1.2.RELEASE.jar:na]
at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:168) ~[spring-retry-1.1.2.RELEASE.jar:na]
at org.springframework.retry.interceptor.RetryOperationsInterceptor.invoke(RetryOperationsInterceptor.java:98) ~[spring-retry-1.1.2.RELEASE.jar:na]
at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.invoke(AnnotationAwareRetryOperationsInterceptor.java:118) ~[spring-retry-1.1.2.RELEASE.jar:na]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656) ~[spring-aop-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at com.cfa.fulfillmentApi.delegate.OrderRequestDelegate$$EnhancerBySpringCGLIB$ec8aa9.processItem(<generated>) ~[classes/:na]
at com.cfa.fulfillmentApi.controller.OrderRequestController.get(OrderRequestController.java:45) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_112]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_112]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_112]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_112]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:220) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846) ~[spring-webmvc-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-embed-websocket-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55) ~[spring-boot-1.4.3.RELEASE.jar:1.4.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:105) ~[spring-boot-actuator-1.4.3.RELEASE.jar:1.4.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:89) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:106) ~[spring-boot-actuator-1.4.3.RELEASE.jar:1.4.3.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.5.RELEASE.jar:4.3.5.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:108) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:784) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:802) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1410) [tomcat-embed-core-8.5.6.jar:8.5.6]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.6.jar:8.5.6]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_112]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_112]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.6.jar:8.5.6]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_112]
这是该答案中的完整应用程序,已修改为与您的应用程序功能相同;如果您仍然无法找出问题所在,请使用完整配置和调试日志编辑您的问题。
@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");
System.out.println("Recovered");
}
catch (Exception e) {
System.out.println("Not recovered: " + e);
}
try {
bean.out("bar");
}
catch (Exception e) {
System.out.println("Not recovered: " + e);
}
}
@Component
public static class Foo {
@Retryable(include=NoResultException.class, backoff = @Backoff(delay = 100, maxDelay = 101), maxAttempts = 5)
public void out(String foo) {
System.out.println(foo);
if (foo.equals("foo")) {
throw new NoResultException();
}
else {
throw new IllegalStateException();
}
}
@Recover
public void connectionException(NoResultException e) {
System.out.println("Retry failure");
}
@Recover
public void connectionException(Exception e) throws Exception {
System.out.println("Retry failure");
throw e;
}
}
}
结果(使用 o.s.retry
的 DEBUG 日志记录)
14:16:25.803 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=0
foo
14:16:25.913 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=1
14:16:25.914 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=1
foo
14:16:26.017 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=2
14:16:26.017 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=2
foo
14:16:26.121 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=3
14:16:26.121 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=3
foo
14:16:26.223 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=4
14:16:26.223 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=4
foo
14:16:26.224 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=5
14:16:26.224 [main] DEBUG o.s.retry.support.RetryTemplate - Retry failed last attempt: count=5
Retry failure
Recovered
14:16:26.224 [main] DEBUG o.s.retry.support.RetryTemplate - Retry: count=0
bar
14:16:26.225 [main] DEBUG o.s.retry.support.RetryTemplate - Checking for rethrow: count=1
14:16:26.225 [main] DEBUG o.s.retry.support.RetryTemplate - Retry failed last attempt: count=1
Retry failure
Not recovered: java.lang.IllegalStateException
看来你和我一样只是错过了基础部分。
用@Recover注解的方法应该采用相同类型的参数(以及可选的Throwable或其子类类型参数)。除此之外 return 类型也应该相同。
下面是您的恢复方法在重试耗尽后应该如何被触发。
@Component
public static class Foo {
@Retryable(include=NoResultException.class, backoff = `@Backoff(delay = 100, maxDelay = 101), maxAttempts = 5)`
public void out(String foo) {
System.out.println(foo);
if (foo.equals("foo")) {
throw new NoResultException();
}
else {
throw new IllegalStateException();
}
}
@Recover
public void connectionException(NoResultException e, String foo) {
System.out.println("Retry failure");
}
@Recover
public void connectionException(Exception e, String foo) throws Exception {
System.out.println("Retry failure");
throw e;
}
}