java - Spring AOP : aspect @Around doesn't work

标签 java aop spring-aop

我使用 Spring Boot 和 Spring Initializr 制作了一个简单的 Web 应用程序,并尝试编写 @Aspect @左右建议。

当我添加自定义注释时 @RetryOnFailure 到 Controller 的端点方法 - 它可以工作,但是当我将此注释添加到 Controller 端点执行的 Controller 方法时 - 它不起作用。我花了很多时间来了解这种行为的原因,但没有任何结果。所以请帮忙。

项目地址: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);
}

最佳答案

您犯了一个典型的 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() 绑定(bind)到通知参数,
  • 当通知被触发时记录连接点和
  • 在尝试 #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
    

    关于java - Spring AOP : aspect @Around doesn't work,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42733826/

    相关文章:

    java - Eclipse IDE 设置仅类的方法在包资源管理器中可见

    java - 以 JSON 对象作为数据的 HTTP POST 请求

    java - Spring aop不止一种方法

    java - 将元数据添加到 java throwable 对象

    java - 是否可以将 Spring Security 的 AOP 与 Java Security Manager 合并?

    java - 为什么我的 Facelets 循环变量不会超出范围?

    java - Hibernate 有时不提取 uuid 引用的实体

    actionscript-3 - Actionscript 3 的面向方面的编程库/框架?

    java - AspectJ:变量从一个匹配建议转移到另一个匹配建议

    java - 从Spring AOP转换为AspectJ