AspectJ - 尝试包装使用一个注释注释的方法,但不包含其他

时间:2015-07-09 01:16:52

标签: java spring aop aspectj spring-aop

我想用@ Annotation1包装所有注释的方法,但不包括@ Annotation2。

到目前为止,我尝试了3种方法,但都失败了。第一个是切入点表达式。例如:

@Before("@annotation(Annotation1) && !@annotation(Annotation2)")
public void doTheWrapping() {
    System.out.println("Wrapped!");
}

无论Annotation2如何,此方法都会包含使用Annotation1注释的所有内容。

第二种方法是手动检测Annotation2,但这似乎也不起作用。

@Before("@annotation(Annotation1)")
public void doTheWrapping(final JoinPoint joinPoint) {
    Method method = MethodSignature.class.cast(joinPoint.getSignature()).getMethod();

    if (AnnotationUtils.getAnnotation(method, Annotation2.class) == null) {
        System.out.println("Wrapped!");
    }
}

这会失败,因为AnnotationUtils.getAnnotations(method)始终返回null。它似乎根本不知道该方法的注释。

最后,我尝试使用@Pointcuts。

@Pointcut("execution(@Annotation1 * *(..))")
public void annotatedWithAnnotation1() {}

@Pointcut("execution(@Annotation2 * *(..))")
public void annotatedWithAnnotation2() {}

@Before("annotatedWithAnnotation1() && !annotatedWithAnnotation2()")
public void doTheWrapping() {
    System.out.println("Wrapped!");
}

再一次,无论Annotation2如何,都会包装所有内容。

有人可以帮忙吗?

事实证明答案真的很简单。将@ Annotation2移动到接口而不是实现解决了这个问题。

1 个答案:

答案 0 :(得分:1)

只要方面与两个注释位于同一个包中,您的第一个切入点就应该有效。否则,您需要指定完全限定的类名。这是一个独立的AspectJ示例。在Spring AOP中它应该是相同的:

package de.scrum_master.app;

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

@Retention(RetentionPolicy.RUNTIME)
public @interface Annotation1 {}
package de.scrum_master.app;

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

@Retention(RetentionPolicy.RUNTIME)
public @interface Annotation2 {}
package de.scrum_master.app;

public class Application {
    @Annotation1
    public void foo() {}

    @Annotation2
    public void bar() {}

    @Annotation1
    @Annotation2
    public void zot() {}

    public void baz() {}

    public static void main(String[] args) {
        Application application = new Application();
        application.foo();
        application.bar();
        application.zot();
        application.bar();
    }
}
package de.scrum_master.aspect;

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

@Aspect
public class MyAspect {
    @Before("@annotation(de.scrum_master.app.Annotation1) && !@annotation(de.scrum_master.app.Annotation2)")
    public void doTheWrapping(JoinPoint thisJoinPoint) {
        System.out.println(thisJoinPoint);
    }
}

AspectJ的控制台输出:

call(void de.scrum_master.app.Application.foo())
execution(void de.scrum_master.app.Application.foo())

Spring AOP的控制台输出:

由于Spring AOP不支持call()切入点,因此只要execution()Application@Component,就会拦截execution(void de.scrum_master.app.Application.foo()) 个连接点:

public abstract class A
{
}

public class B : A
{
    public B()
    {
        Console.WriteLine("I am of type B!");
    }
}
public class C : A
{
    public C()
    {
        Console.WriteLine("I am of type C!");
    }
}

static List<A> listOfStuff = new List<A>();
public static void doSomething()
{
    listOfStuff.Add(new B());
    listOfStuff.Add(new C());

    foreach (A item in listOfStuff)
    {
        doOperation(item);
    }
}
static void doOperation(A thing1)
{
    if (thing1 is B)
    {
        //Do code for B
    }

    if (thing1 is C)
    {
        //Do code for C
    }
}