AspectJ指示符@args()无法在Spring AOP中工作

时间:2017-04-02 06:12:07

标签: java spring aop spring-aop aspect

我正在学习Spring,我搜索了很多关于如何正确使用@args()AspectJ指示符但我仍然不完全清楚。我所知道的是它限制了联合点匹配,以执行其参数使用给定注释类型注释的方法。这在我的案例中似乎不起作用。

所以这里是我的文件:

Human.java

@Component
public class Human {
    int sleepHours;
    public int sleep(String sleepHours) {
        this.sleepHours = Integer.parseInt(sleepHours);
        System.out.println("Humans sleep for " + this.sleepHours + " hours.");
        return this.sleepHours+1;
    }
}

Sleepable.java - 可注册的注释

 package com.aspect;
 public @interface Sleepable {

 }

SleepingAspect.java - 方面

@Component
@Aspect
public class SleepingAspect {

    @Pointcut("@args(com.aspect.Sleepable)")
    public void sleep(){};

    @Before("sleep()")
    public void beforeSleep() {
        System.out.println("Closing eyes before sleeping");
    }

    @AfterReturning("sleep()")
    public void afterSleep() {
        System.out.println("Opening eyes after sleep");
    }
}

MainApp.java

public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        Human human = (Human) context.getBean("human");
        @Sleepable
        String sleepHours = "8";
        human.sleep(sleepHours);
    }
}

输出

人类睡了8个小时。

预期输出

睡觉前闭上眼睛

人类睡了8个小时。

睡觉后睁开眼睛

1 个答案:

答案 0 :(得分:1)

您的代码中有几个错误:

  • Spring AOP只能截取Spring组件的方法调用。您要拦截的是对局部变量的注释。甚至更强大的AspectJ也不能拦截任何有关局部变量的内容,只能读取/写入类成员的访问权限。因此,你想做的事情是不可能的。顺便说一句,它是糟糕的应用程序设计。在尝试应用横切行为时,为什么有人想要依赖方法内部?方法内部结构经常进行重构。建议:将注释放在方法public int sleep(String sleepHours)
  • 您的注释在运行时是不可见的,因为您忘记添加@Retention(RetentionPolicy.RUNTIME)之类的元注释。
  • @args是错误的切入点类型。它捕获方法参数,其类型被注释。您想改用@annotation(com.aspect.Sleepable)

我认为你不应该试试副本&使用Spring AOP粘贴冷启动,但首先阅读Spring AOP manual。我在这里解释的一切都可以在那里找到。

更新:根据您的评论,您只是在练习并尝试为@args()编写示例。这是一个简单的AspectJ。您可以在Spring AOP中以类似的形式轻松使用它。 @Before建议向您展示如何在其类上使用注释匹配参数,@After建议还显示如何将相应的注释绑定到建议参数。

使用它的注释+类:

package com.company.app;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}
package com.company.app;

@MyAnnotation
public class MyClass {}

驱动程序应用程序:

package com.company.app;

public class Application {
  public static void main(String[] args) {
    new Application().doSomething(new MyClass(), 11);
  }

  public String doSomething(MyClass myClass, int i) {
    return "blah";
  }
}

如您所见,这里我们在方法参数中使用带注释的类MyClass。这可以在以下方面与@args()匹配。

<强>方面:

package com.company.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import com.company.app.MyAnnotation;

@Aspect
public class MyAspect {
  @Before("@args(com.company.app.MyAnnotation, ..)")
  public void myBeforeAdvice(JoinPoint thisJoinPoint) {
    System.out.println("Before " + thisJoinPoint);
  }

  @After("@args(myAnnotation, ..)")
  public void myAfterAdvice(JoinPoint thisJoinPoint, MyAnnotation myAnnotation) {
    System.out.println("After " + thisJoinPoint + " -> " + myAnnotation);
  }
}

控制台日志:

Before call(String com.company.app.Application.doSomething(MyClass, int))
Before execution(String com.company.app.Application.doSomething(MyClass, int))
After execution(String com.company.app.Application.doSomething(MyClass, int)) -> @com.company.app.MyAnnotation()
After call(String com.company.app.Application.doSomething(MyClass, int)) -> @com.company.app.MyAnnotation()

当然,Spring {AOP中的call()个连接点不可用,所以你只能看到两行日志输出。