我试图通过Spring Aop AspectJ样式获取注释的值,其中注释可以在类或方法上。我尝试了很多不同的东西,但是当注释在方法上时我才能使它工作。我真的想在类上注释ONCE - 但是建议类的所有方法 - 并在通知中访问类注释的值。这是我最终的结果:
注释:
@Inherited
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "";
}
方面:
@Aspect
public class MyAspect {
@Pointcut("execution(@com.myco.MyAnnotation * com.myco.somepackage..*.*(..))")
public void atExecution() { }
@Before("atExecution() && @annotation(myAnnotation)")
public void myAdvice(JoinPoint joinPoint, MyAnnotation myAnnotation) {
...
}
}
有什么想法?感谢。
答案 0 :(得分:3)
虽然您可以同时制定与 直接注释的方法和注释类型的方法匹配的切入点,但您无法制作一个切入点和/或建议,其中绑定注释的值(即使用建议代码中的注释值)。
@Aspect
public class MyAspect {
@Pointcut("execution(@com.myco.MyAnnotation * com.myco.somepackage..*.*(..))")
public void atExecutionOfAnnotatedMethod() {}
@Pointcut("execution(* (@com.myco.MyAnnotation com.myco.somepackage..*).*(..))")
public void atExecutionOfMethodsOfAnnotatedClass() {}
@Before("atExecutionOfAnnotatedMethod() && @annotation(myAnnotation)")
public void myAdviceForMethodAnnotation(JoinPoint joinPoint, MyAnnotation myAnnotation) {
System.out.println("myAdviceForMethodAnnotation: " + myAnnotation.value());
}
@Before("atExecutionOfMethodsOfAnnotatedClass() && @this(myAnnotation)")
public void myAdviceForTypeAnnotation(JoinPoint joinPoint, MyAnnotation myAnnotation) {
System.out.println("myAdviceForTypeAnnotation: " + myAnnotation.value());
}
// /* the following pointcut will result in "inconsistent binding" errors */
// @Pointcut("(atExecutionOfAnnotatedMethod() && @annotation(myMethodAnnotation)) || (atExecutionOfMethodsOfAnnotatedClass() && @this(myTypeAnnotation))")
// public void combinedPointcut(MyAnnotation myMethodAnnotation, MyAnnotation myTypeAnnotation) {}
}
要合并两个单独的切入点(atExecutionOfAnnotatedMethod
和atExecutionOfMethodsOfAnnotatedClass
),我们必须使用OR(||
)构造。由于OR构造不保证在建议执行时两个注释绑定中的任何一个都存在,它们都将导致编译错误(不一致绑定)。
您仍然可以在单独的建议中处理这两种情况,您也可以将实际的建议代码委托给一个通用方法以避免重复。在这种情况下,您需要处理两者类型和方法使用@MyAnnotation
注释的情况,因为这将与两个切入点匹配,并且会导致您的方法被双重建议这两个建议,因此您的常见建议处理代码将执行两次。
如果您需要结合这两种情况,同时防止双重建议目标代码,则需要在方法级别注释和类级别注释之间设置优先级。基于特异性原则,我建议继续使用方法级别注释优先于类级别1的路径。你的方面看起来像这样:
@Aspect
public class MyCombinedAspect {
@Pointcut("execution(@com.myco.MyAnnotation * com.myco.somepackage..*.*(..))")
public void atExecutionOfAnnotatedMethod() {}
@Pointcut("execution(* (@com.myco.MyAnnotation com.myco.somepackage..*).*(..))")
public void atExecutionOfMethodsOfAnnotatedClass() {}
@Before("atExecutionOfAnnotatedMethod() && !atExecutionOfMethodsOfAnnotatedClass() && @annotation(myAnnotation)")
public void myAdviceForMethodAnnotation(JoinPoint joinPoint, MyAnnotation myAnnotation) {
handleBeforeExecution(joinPoint, myAnnotation);
}
@Before("atExecutionOfMethodsOfAnnotatedClass() && !atExecutionOfAnnotatedMethod() && @this(myAnnotation)")
public void myAdviceForTypeAnnotation(JoinPoint joinPoint, MyAnnotation myAnnotation) {
handleBeforeExecution(joinPoint, myAnnotation);
}
@Before("atExecutionOfMethodsOfAnnotatedClass() && atExecutionOfAnnotatedMethod() && @annotation(myMethodAnnotation)")
public void myAdviceForDoublyAnnotated(JoinPoint joinPoint, MyAnnotation myMethodAnnotation) {
handleBeforeExecution(joinPoint, myMethodAnnotation);
}
protected void handleBeforeExecution(JoinPoint joinPoint, MyAnnotation myAnnotation) {
System.out.println(myAnnotation.value());
}