我使用Spring Boot和Spring Initializr创建了一个简单的Web应用程序,并尝试使用 @Around 建议编写 @Aspect 。
当我将自定义注释 @RetryOnFailure 添加到控制器'端点方法 - 它可以工作,但是当我将这个注释添加到控制器时#39;方法,由控制器端点执行 - 它不起作用。我花了很多时间来理解这种行为的原因,但没有任何结果。所以请帮忙。
项目位于此处:https://github.com/zalizko/spring-aop-playground
@Aspect
@Component
public final class MethodRepeater {
@Around("execution(* *(..)) && @annotation(RetryOnFailure)")
public Object wrap(final ProceedingJoinPoint joinPoint) throws Throwable {
// code is here
}
}
所以,我的目标是:
@RequestMapping
public String index() {
inTry();
return "OK";
}
@RetryOnFailure(attempts = 3, delay = 2, unit = TimeUnit.SECONDS)
public void inTry() {
throw new RuntimeException("Exception in try " + ++counter);
}
答案 0 :(得分:4)
你做了一个典型的Spring AOP初学者'错误:您忘记了基于代理的AOP仅在从外部调用代理方法时才有效,而不是通过this
(避免代理)。但内部通话inTry()
与this.inTry()
相同。因此,方面永远不会触发inTry
,您必须重新排列代码:
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);
}
}
我也改变了方面以便
@annotation()
,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());
}
}
}
}
现在它可以工作,控制台日志说:
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
答案 1 :(得分:0)
我遇到了类似的问题,我设法使用AspectJ来解决它:
https://github.com/mdanetzky/tour-of-heroes-java
另外 - 我花了一些时间才发现,我的IDEA没有正确地重建方面,所以在你尝试一些更激烈的措施之前,尝试清理/重建项目可能是值得的。