You made a typical Spring AOP beginners' mistake: You forgot that proxy-based AOP only works if proxy methods are called from outside, not via this
(avoiding the proxy). But the internal call inTry()
is the same as this.inTry()
. Thus, the aspect never triggers for inTry
and you have to rearrange your code like this:
package spring.aop;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
@RestController("/")
public class HomeController {
static int counter = 0;
@RequestMapping
@RetryOnFailure(attempts = 3, delay = 2, unit = TimeUnit.SECONDS)
public String index() {
throw new RuntimeException("Exception in try " + ++counter);
}
}
I also changed the aspect a little bit so as to
- avoid reflection and bind the annotation to an advice parameter directly via
@annotation()
,
- log the joinpoint when the advice is triggered and
- return "OK" on try #3 (just for fun, not necessary).
package spring.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public final class MethodRepeater {
@Around("execution(* spring.aop..*(..)) && @annotation(retryOnFailure)")
public Object wrap(final ProceedingJoinPoint joinPoint, RetryOnFailure retryOnFailure) throws Throwable {
System.out.println(joinPoint);
return proceed(joinPoint, retryOnFailure);
}
private Object proceed(ProceedingJoinPoint joinPoint, RetryOnFailure retryOnFailure) throws Throwable {
int attempt = 1;
while (true) {
try {
return joinPoint.proceed();
} catch (final Throwable ex) {
System.out.println("Try #" + attempt + " failed: " + ex);
if (++attempt >= retryOnFailure.attempts())
return "OK";
if (retryOnFailure.delay() > 0L)
retryOnFailure.unit().sleep(retryOnFailure.delay());
}
}
}
}
Now it works and the console log says:
execution(String spring.aop.HomeController.index())
Try #1 failed: java.lang.RuntimeException: Exception in try 1
Try #2 failed: java.lang.RuntimeException: Exception in try 2
inTry()
always throws an exception. Does that make any sense? – Taco