diff --git a/spring-context/src/main/java/org/springframework/resilience/retry/AbstractRetryInterceptor.java b/spring-context/src/main/java/org/springframework/resilience/retry/AbstractRetryInterceptor.java index 762c5612f42..a74385a87cc 100644 --- a/spring-context/src/main/java/org/springframework/resilience/retry/AbstractRetryInterceptor.java +++ b/spring-context/src/main/java/org/springframework/resilience/retry/AbstractRetryInterceptor.java @@ -26,6 +26,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.util.retry.Retry; +import org.springframework.aop.ProxyMethodInvocation; import org.springframework.core.ReactiveAdapter; import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.core.retry.RetryException; @@ -103,7 +104,8 @@ public abstract class AbstractRetryInterceptor implements MethodInterceptor { return retryTemplate.execute(new Retryable<>() { @Override public @Nullable Object execute() throws Throwable { - return invocation.proceed(); + return (invocation instanceof ProxyMethodInvocation pmi ? + pmi.invocableClone().proceed() : invocation.proceed()); } @Override public String getName() { diff --git a/spring-context/src/test/java/org/springframework/resilience/RetryInterceptorTests.java b/spring-context/src/test/java/org/springframework/resilience/RetryInterceptorTests.java index f981bfae4ad..e637c297fa5 100644 --- a/spring-context/src/test/java/org/springframework/resilience/RetryInterceptorTests.java +++ b/spring-context/src/test/java/org/springframework/resilience/RetryInterceptorTests.java @@ -17,18 +17,21 @@ package org.springframework.resilience; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.file.AccessDeniedException; import java.time.Duration; import java.util.Properties; import java.util.concurrent.atomic.AtomicInteger; +import org.aopalliance.intercept.MethodInterceptor; import org.junit.jupiter.api.Test; import org.springframework.aop.framework.AopProxyUtils; import org.springframework.aop.framework.ProxyConfig; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.framework.autoproxy.AutoProxyUtils; +import org.springframework.aop.interceptor.SimpleTraceInterceptor; import org.springframework.aop.support.AopUtils; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; @@ -59,7 +62,30 @@ class RetryInterceptorTests { pf.setTarget(target); pf.addAdvice(new SimpleRetryInterceptor( new MethodRetrySpec((m, t) -> true, 5, Duration.ofMillis(10)))); - NonAnnotatedBean proxy = (NonAnnotatedBean) pf.getProxy(); + pf.addAdvice(new SimpleTraceInterceptor()); + PlainInterface proxy = (PlainInterface) pf.getProxy(); + + assertThatIOException().isThrownBy(proxy::retryOperation).withMessage("6"); + assertThat(target.counter).isEqualTo(6); + } + + @Test + void withSimpleInterceptorAndNoTarget() { + NonAnnotatedBean target = new NonAnnotatedBean(); + ProxyFactory pf = new ProxyFactory(); + pf.addAdvice(new SimpleRetryInterceptor( + new MethodRetrySpec((m, t) -> true, 5, Duration.ofMillis(10)))); + pf.addAdvice(new SimpleTraceInterceptor()); + pf.addAdvice((MethodInterceptor) invocation -> { + try { + return invocation.getMethod().invoke(target, invocation.getArguments()); + } + catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + }); + pf.addInterface(PlainInterface.class); + PlainInterface proxy = (PlainInterface) pf.getProxy(); assertThatIOException().isThrownBy(proxy::retryOperation).withMessage("6"); assertThat(target.counter).isEqualTo(6); @@ -237,7 +263,7 @@ class RetryInterceptorTests { } - static class NonAnnotatedBean { + static class NonAnnotatedBean implements PlainInterface { int counter = 0; @@ -248,6 +274,12 @@ class RetryInterceptorTests { } + public interface PlainInterface { + + void retryOperation() throws IOException; + } + + static class AnnotatedMethodBean { int counter = 0;