diff --git a/src/main/java/org/springframework/retry/annotation/AnnotationAwareRetryOperationsInterceptor.java b/src/main/java/org/springframework/retry/annotation/AnnotationAwareRetryOperationsInterceptor.java index d25d850..9b800f5 100644 --- a/src/main/java/org/springframework/retry/annotation/AnnotationAwareRetryOperationsInterceptor.java +++ b/src/main/java/org/springframework/retry/annotation/AnnotationAwareRetryOperationsInterceptor.java @@ -93,7 +93,7 @@ public class AnnotationAwareRetryOperationsInterceptor implements IntroductionIn private BeanFactory beanFactory; - private RetryListener[] listeners; + private RetryListener[] defaultListeners; /** * @param sleeper the sleeper to set @@ -127,12 +127,12 @@ public class AnnotationAwareRetryOperationsInterceptor implements IntroductionIn /** * Retry listeners to apply to all operations. - * @param listeners the listeners + * @param defaultListeners the listeners */ - public void setListeners(Collection listeners) { - ArrayList retryListeners = new ArrayList(listeners); + public void setDefaultListeners(Collection defaultListeners) { + ArrayList retryListeners = new ArrayList(defaultListeners); AnnotationAwareOrderComparator.sort(retryListeners); - this.listeners = retryListeners.toArray(new RetryListener[0]); + this.defaultListeners = retryListeners.toArray(new RetryListener[0]); } @Override @@ -208,7 +208,7 @@ public class AnnotationAwareRetryOperationsInterceptor implements IntroductionIn } private MethodInterceptor getStatelessInterceptor(Object target, Method method, Retryable retryable) { - RetryTemplate template = createTemplate(); + RetryTemplate template = createTemplate(retryable.listeners()); template.setRetryPolicy(getRetryPolicy(retryable)); template.setBackOffPolicy(getBackoffPolicy(retryable.backoff())); return RetryInterceptorBuilder.stateless() @@ -219,7 +219,7 @@ public class AnnotationAwareRetryOperationsInterceptor implements IntroductionIn } private MethodInterceptor getStatefulInterceptor(Object target, Method method, Retryable retryable) { - RetryTemplate template = createTemplate(); + RetryTemplate template = createTemplate(retryable.listeners()); template.setRetryContextCache(this.retryContextCache); CircuitBreaker circuit = AnnotationUtils.findAnnotation(method, CircuitBreaker.class); @@ -254,14 +254,24 @@ public class AnnotationAwareRetryOperationsInterceptor implements IntroductionIn .build(); } - private RetryTemplate createTemplate() { + private RetryTemplate createTemplate(String[] listenersBeanNames) { RetryTemplate template = new RetryTemplate(); - if (listeners!=null) { - template.setListeners(listeners); + if (listenersBeanNames.length > 0) { + template.setListeners(getListenersBeans(listenersBeanNames)); + } else if (defaultListeners !=null) { + template.setListeners(defaultListeners); } return template; } + private RetryListener[] getListenersBeans(String[] listenersBeanNames) { + RetryListener[] listeners = new RetryListener[listenersBeanNames.length]; + for (int i = 0; i < listeners.length; i++) { + listeners[i] = beanFactory.getBean(listenersBeanNames[i], RetryListener.class); + } + return listeners; + } + 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 bf95264..8ca6d40 100644 --- a/src/main/java/org/springframework/retry/annotation/RetryConfiguration.java +++ b/src/main/java/org/springframework/retry/annotation/RetryConfiguration.java @@ -134,7 +134,7 @@ public class RetryConfiguration extends AbstractPointcutAdvisor implements Intro interceptor.setRetryContextCache(retryContextCache); } if (retryListeners != null) { - interceptor.setListeners(retryListeners); + interceptor.setDefaultListeners(retryListeners); } if (methodArgumentsKeyGenerator != null) { interceptor.setKeyGenerator(methodArgumentsKeyGenerator); diff --git a/src/main/java/org/springframework/retry/annotation/Retryable.java b/src/main/java/org/springframework/retry/annotation/Retryable.java index ccd04f7..0b80d07 100644 --- a/src/main/java/org/springframework/retry/annotation/Retryable.java +++ b/src/main/java/org/springframework/retry/annotation/Retryable.java @@ -118,4 +118,10 @@ public @interface Retryable { */ String exceptionExpression() default ""; + /** + * Bean names of retry listeners to use instead of default ones defined in Spring context + * @return retry listeners bean names + */ + String[] listeners() default {}; + } diff --git a/src/test/java/org/springframework/retry/annotation/EnableRetryWithListenersTests.java b/src/test/java/org/springframework/retry/annotation/EnableRetryWithListenersTests.java index e4bf3d1..b140249 100644 --- a/src/test/java/org/springframework/retry/annotation/EnableRetryWithListenersTests.java +++ b/src/test/java/org/springframework/retry/annotation/EnableRetryWithListenersTests.java @@ -43,6 +43,17 @@ public class EnableRetryWithListenersTests { context.close(); } + @Test + public void overrideListener() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( + TestConfigurationMultipleListeners.class); + ServiceWithOverriddenListener service = context.getBean(ServiceWithOverriddenListener.class); + service.service(); + assertEquals(1, context.getBean(TestConfigurationMultipleListeners.class).count1); + assertEquals(0, context.getBean(TestConfigurationMultipleListeners.class).count2); + context.close(); + } + @Configuration @EnableRetry(proxyTargetClass = true) protected static class TestConfiguration { @@ -67,6 +78,42 @@ public class EnableRetryWithListenersTests { } + @Configuration + @EnableRetry(proxyTargetClass = true) + protected static class TestConfigurationMultipleListeners { + + private int count1 = 0; + private int count2 = 0; + + @Bean + public ServiceWithOverriddenListener service() { + return new ServiceWithOverriddenListener(); + } + + @Bean + public RetryListener listener1() { + return new RetryListenerSupport() { + @Override + public void close(RetryContext context, + RetryCallback callback, Throwable throwable) { + count1++; + } + }; + } + + @Bean + public RetryListener listener2() { + return new RetryListenerSupport() { + @Override + public void close(RetryContext context, + RetryCallback callback, Throwable throwable) { + count2++; + } + }; + } + + } + protected static class Service { private int count = 0; @@ -84,4 +131,21 @@ public class EnableRetryWithListenersTests { } + protected static class ServiceWithOverriddenListener { + + private int count = 0; + + @Retryable(backoff = @Backoff(delay = 1000), listeners = "listener1") + public void service() { + if (count++ < 2) { + throw new RuntimeException("Planned"); + } + } + + public int getCount() { + return count; + } + + } + }