【问题标题】:Spring AspectJ, pointcut before method execution where method OR class is annotatedSpring AspectJ,方法执行之前的切入点,其中方法或类被注释
【发布时间】:2015-12-15 13:09:04
【问题描述】:

我正在尝试通过 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) {
        ...
    }
}

有什么想法吗?谢谢。

【问题讨论】:

    标签: spring aspectj spring-aop


    【解决方案1】:

    简答

    虽然您可以制定一个同时匹配 直接带注释的方法带注释类型的方法的切入点,但您不能您绑定注释值的切入点和/或建议(即在建议代码中使用注释值)。

    @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) {}
    
    }
    

    一些细节

    要组合两个单独的切入点(atExecutionOfAnnotatedMethodatExecutionOfMethodsOfAnnotatedClass),我们必须使用 OR (||) 构造。由于 OR 构造不保证两个注解绑定中的任何一个都将出现在通知执行时,它们都会导致编译错误(不一致的绑定)。 您仍然可以在单独的建议中处理这两种情况,您也可以将实际的建议代码委托给一个通用方法以避免重复。在这种情况下,您需要注意 both 类型和方法都使用 @MyAnnotation 注释的情况,因为这将匹配两个切入点,并导致您的方法受到两个建议的双重建议,因此您的常见建议处理代码将执行两次。

    两者结合

    如果你需要结合这两种情况,同时防止双重通知目标代码,你需要在方法级注解和类级注解之间设置一个优先级。基于特异性原则,我建议走方法级注释优先于类一级的路线。你的方面看起来像这样:

    @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());
        }
    

    【讨论】:

    • 感谢您的回复。非常详细。所以要澄清。我可以按照您的指示使用两个不同的建议来执行此操作,但需要注意不要同时注释类和方法。 (这将很难执行)。再次感谢!
    • 没有。让我澄清一下。注释类或方法足够。但是我们不能强制开发人员不会同时注释类和方法。在这种情况下,我们希望方法注释生效。因此,我们有 3 条建议来处理 3 种情况,按顺序:1-仅注释方法时,2-仅注释类时,3-同时注释方法和类时,在这种情况下方法注释的值被传递 给委托方法。所有三个建议都委托给相同的方法来完成工作,以遵守 DRY 原则。
    • 我回答中的第二个方面与我在之前的评论中描述的方式相同。希望这能消除最终的困惑。
    • 知道了。再次感谢所有的细节。真的很有帮助。
    猜你喜欢
    • 2020-07-28
    • 1970-01-01
    • 2013-02-12
    • 2013-02-12
    • 1970-01-01
    • 1970-01-01
    • 2015-11-06
    • 2018-05-08
    相关资源
    最近更新 更多