From 1cb4f19cf19dbfade8b9c103b30c359db9be8360 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 22 Aug 2016 11:37:07 +0100 Subject: [PATCH] Add support for RetryListener beans in @EnableRetry --- ...tationAwareRetryOperationsInterceptor.java | 30 +++++++++++++++++-- .../retry/annotation/RetryConfiguration.java | 8 +++++ .../retry/support/RetryTemplate.java | 11 +++---- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/springframework/retry/annotation/AnnotationAwareRetryOperationsInterceptor.java b/src/main/java/org/springframework/retry/annotation/AnnotationAwareRetryOperationsInterceptor.java index 380ad94..737a8cf 100644 --- a/src/main/java/org/springframework/retry/annotation/AnnotationAwareRetryOperationsInterceptor.java +++ b/src/main/java/org/springframework/retry/annotation/AnnotationAwareRetryOperationsInterceptor.java @@ -18,6 +18,8 @@ package org.springframework.retry.annotation; import java.lang.annotation.Annotation; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; @@ -28,7 +30,9 @@ import org.springframework.aop.IntroductionInterceptor; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.retry.RetryListener; import org.springframework.retry.RetryPolicy; import org.springframework.retry.backoff.BackOffPolicy; import org.springframework.retry.backoff.ExponentialBackOffPolicy; @@ -74,6 +78,8 @@ public class AnnotationAwareRetryOperationsInterceptor implements IntroductionIn private BeanFactory beanFactory; + private RetryListener[] listeners; + /** * @param sleeper the sleeper to set */ @@ -104,6 +110,16 @@ public class AnnotationAwareRetryOperationsInterceptor implements IntroductionIn this.newMethodArgumentsIdentifier = newMethodArgumentsIdentifier; } + /** + * Retry listeners to apply to all operations. + * @param listeners the listeners + */ + public void setListeners(Collection listeners) { + ArrayList retryListeners = new ArrayList(listeners); + AnnotationAwareOrderComparator.sort(retryListeners); + this.listeners = retryListeners.toArray(new RetryListener[0]); + } + @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; @@ -167,15 +183,17 @@ public class AnnotationAwareRetryOperationsInterceptor implements IntroductionIn } private MethodInterceptor getStatelessInterceptor(Object target, Method method, Retryable retryable) { + RetryTemplate template = createTemplate(); + template.setRetryPolicy(getRetryPolicy(retryable)); + template.setBackOffPolicy(getBackoffPolicy(retryable.backoff())); return RetryInterceptorBuilder.stateless() - .retryPolicy(getRetryPolicy(retryable)) - .backOffPolicy(getBackoffPolicy(retryable.backoff())) + .retryOperations(template) .recoverer(getRecoverer(target, method)) .build(); } private MethodInterceptor getStatefulInterceptor(Object target, Method method, Retryable retryable) { - RetryTemplate template = new RetryTemplate(); + RetryTemplate template = createTemplate(); template.setRetryContextCache(this.retryContextCache); CircuitBreaker circuit = AnnotationUtils.findAnnotation(method, CircuitBreaker.class); @@ -207,6 +225,12 @@ public class AnnotationAwareRetryOperationsInterceptor implements IntroductionIn .build(); } + private RetryTemplate createTemplate() { + RetryTemplate template = new RetryTemplate(); + template.setListeners(listeners); + return template; + } + private MethodInvocationRecoverer getRecoverer(Object target, Method method) { if (target instanceof MethodInvocationRecoverer) { return (MethodInvocationRecoverer) target; diff --git a/src/main/java/org/springframework/retry/annotation/RetryConfiguration.java b/src/main/java/org/springframework/retry/annotation/RetryConfiguration.java index d65ec62..1c00f47 100644 --- a/src/main/java/org/springframework/retry/annotation/RetryConfiguration.java +++ b/src/main/java/org/springframework/retry/annotation/RetryConfiguration.java @@ -19,6 +19,7 @@ package org.springframework.retry.annotation; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.LinkedHashSet; +import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; @@ -39,6 +40,7 @@ import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.retry.RetryListener; import org.springframework.retry.backoff.Sleeper; import org.springframework.retry.interceptor.MethodArgumentsKeyGenerator; import org.springframework.retry.interceptor.NewMethodArgumentsIdentifier; @@ -68,6 +70,9 @@ public class RetryConfiguration extends AbstractPointcutAdvisor implements Intro @Autowired(required = false) private RetryContextCache retryContextCache; + @Autowired(required = false) + private List retryListeners; + @Autowired(required = false) private MethodArgumentsKeyGenerator methodArgumentsKeyGenerator; @@ -127,6 +132,9 @@ public class RetryConfiguration extends AbstractPointcutAdvisor implements Intro if (retryContextCache != null) { interceptor.setRetryContextCache(retryContextCache); } + if (retryListeners != null) { + interceptor.setListeners(retryListeners); + } if (methodArgumentsKeyGenerator != null) { interceptor.setKeyGenerator(methodArgumentsKeyGenerator); } diff --git a/src/main/java/org/springframework/retry/support/RetryTemplate.java b/src/main/java/org/springframework/retry/support/RetryTemplate.java index dfce612..37895a1 100644 --- a/src/main/java/org/springframework/retry/support/RetryTemplate.java +++ b/src/main/java/org/springframework/retry/support/RetryTemplate.java @@ -208,7 +208,7 @@ public class RetryTemplate implements RetryOperations { @Override public final T execute(RetryCallback retryCallback, RecoveryCallback recoveryCallback, RetryState retryState) - throws E, ExhaustedRetryException { + throws E, ExhaustedRetryException { return doExecute(retryCallback, recoveryCallback, retryState); } @@ -227,7 +227,7 @@ public class RetryTemplate implements RetryOperations { */ protected T doExecute(RetryCallback retryCallback, RecoveryCallback recoveryCallback, RetryState state) - throws E, ExhaustedRetryException { + throws E, ExhaustedRetryException { RetryPolicy retryPolicy = this.retryPolicy; BackOffPolicy backOffPolicy = this.backOffPolicy; @@ -291,8 +291,6 @@ public class RetryTemplate implements RetryOperations { lastException = e; - doOnErrorInterceptors(retryCallback, context, e); - try { registerThrowable(retryPolicy, state, context, e); } @@ -300,6 +298,9 @@ public class RetryTemplate implements RetryOperations { throw new TerminatedRetryException("Could not register throwable", ex); } + finally { + doOnErrorInterceptors(retryCallback, context, e); + } if (canRetry(retryPolicy, context) && !context.isExhaustedOnly()) { try { @@ -469,7 +470,7 @@ public class RetryTemplate implements RetryOperations { private RetryContext doOpenInternal(RetryPolicy retryPolicy, RetryState state) { RetryContext context = retryPolicy.open(RetrySynchronizationManager.getContext()); - if (state!=null) { + if (state != null) { context.setAttribute(RetryContext.STATE_KEY, state.getKey()); } return context;