针对'嵌套'注释的Spring AOP点切割

时间:2015-07-15 20:12:46

标签: java spring annotations aspectj spring-aop

我需要定义一个点切割,它触发在使用自定义注释注释的spring服务的所有方法上执行。我想要定义切入点的注释将在另一个注释上。

@Y
public @interface X {
}

然后该服务将注释为以下

@X
public Service1 {
} 

我尝试使用以下切入点定义,但它只适用于@Y在服务本身上,这意味着它没有看到注释在@X上

@Around("@within(com.mypackage.Y)")

2 个答案:

答案 0 :(得分:5)

我在应用程序中有这个确切的需求。我找到了这个答案,但不满意这无法做到。

经过一番搜索,我发现这个cheat sheet用于AspectJ / Spring切入点表达式。备忘单中的解决方案并不像宣传的那样完全正常,但我能够使它能够满足我的需求。

@Pointcut("within(@(@Annotation *) *)")
public void classAnnotatedWithNestedAnnotationOneLevelDeep() { }

我将此表达式与@within表达式合并为@Annotation以获得我想要的工作。

方法执行:

@Pointcut("execution(@(@com.someorg.SomeAnnotation *) * *(..))")
public void methodAnnotatedWithNestedAnnotationOneLevelDeep() { }

我将此表达式与@annotation表达式合并为@Annotation以获得我想要为方法工作的内容。

答案 1 :(得分:2)

这不是Spring或AspectJ问题。在Java中,接口上的注释,其他注释或方法永远不会通过使用带注释的注释或重写方法实现类,类来继承。注释继承仅适用于类到子类,但前提是超类中使用的注释类型带有元注释@Inherited

更新:因为我之前已经多次回答过这个问题,所以我刚刚记录了问题以及Emulate annotation inheritance for interfaces and methods with AspectJ中的解决方法。

这里有一个小证明,你想要的东西不起作用,因此也不能用于某个方面:

package de.scrum_master.app;

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

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

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

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

import java.lang.annotation.Annotation;

@InnerAnnotation
public class Application {
    public static void main(String[] args) {
        for (Annotation annotation : Application.class.getAnnotations())
            System.out.println(annotation);
    }
}

控制台输出显示JVM只看到内部注释,而不是内部注释使用的外部注释:

@de.scrum_master.app.InnerAnnotation()

更新:Bradley M Handy回答,我重新检查了它是否也适用于我的代码中描述的情况,事实确实如此。这种类型的AspectJ语法对我来说是未知的,尽管我认为我对AspectJ了解很多。谢谢,布拉德利。 :-)这方面可行:

package de.scrum_master.aspect;

import de.scrum_master.app.OuterAnnotation;

public aspect MetaAnnotationAspect {
  after() : within(@(@OuterAnnotation *) *) && execution(* *(..)) {
    System.out.println(thisJoinPoint);
  }
}

运行应用程序时的控制台日志:

@de.scrum_master.app.InnerAnnotation()
execution(void de.scrum_master.app.Application.main(String[]))