From debc4adc9f27a1a671af4ab6507aee10e31569ee Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Sat, 25 Feb 2023 02:36:17 +0800 Subject: [PATCH] GH-22: Add @EnableRetry.order() Fixes https://github.com/spring-projects/spring-retry/issues/22 Configure `@Retryable` before `@Transactional`, so we can handle transaction with stateless retries --- .../retry/annotation/EnableRetry.java | 15 ++++++++++-- .../retry/annotation/RetryConfiguration.java | 23 +++++++++++++++---- .../retry/annotation/EnableRetryTests.java | 23 ++++++++++++++++++- 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/springframework/retry/annotation/EnableRetry.java b/src/main/java/org/springframework/retry/annotation/EnableRetry.java index 79cdc84f..cb90a22f 100644 --- a/src/main/java/org/springframework/retry/annotation/EnableRetry.java +++ b/src/main/java/org/springframework/retry/annotation/EnableRetry.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.Import; +import org.springframework.core.Ordered; import org.springframework.core.annotation.AliasFor; /** @@ -33,7 +34,8 @@ * the annotations. * * @author Dave Syer - * @since 2.0 + * @author Yanming Zhou + * @since 1.1 * */ @Target(ElementType.TYPE) @@ -51,4 +53,13 @@ @AliasFor(annotation = EnableAspectJAutoProxy.class) boolean proxyTargetClass() default false; + /** + * Indicate the order in which the {@link RetryConfiguration} should be applied. + *

+ * The default is {@link Ordered#LOWEST_PRECEDENCE} in order to run after all other + * post-processors, so that it can add an advisor to existing proxies rather than + * double-proxy. + */ + int order() default Ordered.LOWEST_PRECEDENCE; + } diff --git a/src/main/java/org/springframework/retry/annotation/RetryConfiguration.java b/src/main/java/org/springframework/retry/annotation/RetryConfiguration.java index 44af456c..72d9aa53 100644 --- a/src/main/java/org/springframework/retry/annotation/RetryConfiguration.java +++ b/src/main/java/org/springframework/retry/annotation/RetryConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2022 the original author or authors. + * Copyright 2006-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,9 +41,13 @@ import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.ImportAware; import org.springframework.context.annotation.Role; import org.springframework.core.OrderComparator; +import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.lang.Nullable; import org.springframework.retry.RetryListener; import org.springframework.retry.backoff.Sleeper; import org.springframework.retry.interceptor.MethodArgumentsKeyGenerator; @@ -63,6 +67,7 @@ * @author Artem Bilan * @author Markus Heiden * @author Gary Russell + * @author Yanming Zhou * @since 1.1 * */ @@ -70,7 +75,10 @@ @Role(BeanDefinition.ROLE_INFRASTRUCTURE) @Component public class RetryConfiguration extends AbstractPointcutAdvisor - implements IntroductionAdvisor, BeanFactoryAware, InitializingBean, SmartInitializingSingleton { + implements IntroductionAdvisor, BeanFactoryAware, InitializingBean, SmartInitializingSingleton, ImportAware { + + @Nullable + protected AnnotationAttributes enableRetry; private AnnotationAwareRetryOperationsInterceptor advice; @@ -88,6 +96,12 @@ public class RetryConfiguration extends AbstractPointcutAdvisor private BeanFactory beanFactory; + @Override + public void setImportMetadata(AnnotationMetadata importMetadata) { + this.enableRetry = AnnotationAttributes + .fromMap(importMetadata.getAnnotationAttributes(EnableRetry.class.getName())); + } + @Override public void afterPropertiesSet() throws Exception { this.retryContextCache = findBean(RetryContextCache.class); @@ -98,8 +112,9 @@ public void afterPropertiesSet() throws Exception { retryableAnnotationTypes.add(Retryable.class); this.pointcut = buildPointcut(retryableAnnotationTypes); this.advice = buildAdvice(); - if (this.advice instanceof BeanFactoryAware) { - ((BeanFactoryAware) this.advice).setBeanFactory(this.beanFactory); + this.advice.setBeanFactory(this.beanFactory); + if (this.enableRetry != null) { + setOrder(enableRetry.getNumber("order")); } } diff --git a/src/test/java/org/springframework/retry/annotation/EnableRetryTests.java b/src/test/java/org/springframework/retry/annotation/EnableRetryTests.java index ae916416..80232633 100644 --- a/src/test/java/org/springframework/retry/annotation/EnableRetryTests.java +++ b/src/test/java/org/springframework/retry/annotation/EnableRetryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2022 the original author or authors. + * Copyright 2006-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,6 +57,7 @@ * @author Gary Russell * @author Aldo Sinanaj * @author Henning Pƶttker + * @author Yanming Zhou * @since 1.1 */ public class EnableRetryTests { @@ -105,6 +106,15 @@ public void proxyTargetClass() { context.close(); } + @Test + public void order() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( + TestOrderConfiguration.class); + RetryConfiguration config = context.getBean(RetryConfiguration.class); + assertThat(config.getOrder()).isEqualTo(1); + context.close(); + } + @Test public void marker() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TestConfiguration.class); @@ -348,6 +358,17 @@ public int getOrder() { } + @Configuration + @EnableRetry(order = 1) + protected static class TestOrderConfiguration { + + @Bean + public Service service() { + return new Service(); + } + + } + @Configuration @EnableRetry protected static class TestConfiguration {