Spring AOP:方面@Around不起作用

6ioyuze2  于 2023-03-16  发布在  Spring
关注(0)|答案(2)|浏览(643)

我使用Sping Boot 和Spring Initializr制作了一个简单的Web应用程序,并尝试使用**@ Around建议编写@Aspect**。
当我添加我的自定义注解**@RetryOnFailure**到控制器的端点方法时-它工作,但是当我添加这个注解到控制器的方法,由控制器端点执行时-它不工作。我花了很多时间来理解这种行为的原因,但没有任何结果。所以请帮助。
项目位于: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);
}
kuuvgm7e

kuuvgm7e1#

您犯了一个典型的SpringAOP初学者的错误:您忘记了基于代理的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()将注解绑定到通知参数,
  • 在触发通知时记录连接点,以及
  • 在尝试#3时返回“OK”(只是为了好玩,没有必要)。
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
whlutmcx

whlutmcx2#

我遇到过类似的问题,我设法用AspectJ解决了它:
https://github.com/mdanetzky/tour-of-heroes-java
此外-我花了一些时间才发现,我的想法没有正确地重建方面,所以它可能是值得尝试清理/重建项目之前,你尝试一些更激烈的措施。

相关问题