且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

AspectJ指示符@args()在Spring AOP中不起作用

更新时间:2023-08-24 12:11:16

您的代码有几个错误:

  • Spring AOP只能拦截对Spring组件的方法调用.您要拦截的是在局部变量上的注释.甚至功能更强大的AspectJ都不能拦截与局部变量有关的任何内容,而只能拦截对类成员的读/写访问.因此,您试图做的事情是不可能的.顺便说一句,这是糟糕的应用程序设计.为什么有人在尝试应用跨领域行为时想依靠方法内部?方法内部经常进行重构.建议:将注释放在方法public int sleep(String sleepHours)上.
  • 您的注释在运行时不可见,因为您忘记添加像@Retention(RetentionPolicy.RUNTIME)这样的元注释.
  • @args是错误的切入点类型.它捕获方法自变量的类型.您想改用@annotation(com.aspect.Sleepable).
  • Spring AOP can only intercept method calls upon Spring components. What you are trying to intercept is an annotation on a local variable. Not even the much more powerful AspectJ can intercept anything concerning local variables, only read/write access to class members. Thus, what you are trying to do is impossible. And by the way, it is bad application design. Why would anyone want to rely on method internals when trying to apply cross-cutting behaviour? Method internals are subject to frequent refactoring. Suggestion: Put your annotation on method public int sleep(String sleepHours).
  • Your annotation is invisible during runtime because your forgot to add a meta annotation like @Retention(RetentionPolicy.RUNTIME).
  • @args is the wrong pointcut type. It captures method arguments the types of which are annotated. You want to use @annotation(com.aspect.Sleepable) instead.

我认为您不应该尝试复制&从Spring AOP开始粘贴冷启动,但请阅读 Spring AOP手册.我在这里解释的所有内容都可以在此处找到.

I think you should not try a copy & paste cold start with Spring AOP but read the Spring AOP manual first. Everything I explained here can be found there.

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

Update: So according to you comments you were just practicing and trying to make up an example for @args(). Here is one in plain AspectJ. You can easily use it in similar form in Spring AOP. The @Before advice shows you how to match on an argument with an annotation on its class, the @After advice also shows how to bind the corresponding annotation to an advice argument.

使用它的注释+类:

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()匹配.

As you can see, here we use the annotated class MyClass in a method argument. This can be matched with @args() in the following aspect.

方面:

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()

当然,call()连接点在Spring AOP中不可用,因此在那里您只会看到两行日志输出.

Of course, call() joinpoints are unavailable in Spring AOP, so there you would only see two lines of log output.