Spring AOP point cut for 'nested' annotation

丶灬走出姿态 提交于 2019-12-20 03:30:22

问题


I need to define a point cut which triggers the execution on all methods of a spring service annotated with a custom annotation. The annotation I would like to define the point cut on will be on an other annotation.

@Y
public @interface X {
}

and then the service would be annotated as following

@X
public Service1 {
} 

I tried with the following point cut definition but it only works when @Y is on the service itself, meaning that it doesn't see that the annotation is on @X

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

回答1:


This is not a Spring or AspectJ problem. In Java, annotations on interfaces, other annotations or methods are never inherited by implementing classes, classes using annotated annotations or overriding methods. Annotation inheritance only works from classes onto subclasses, but only if the annotation type used in the superclass bears the meta annotation @Inherited.

Update: Because I have answered this question several times before, I have just documented the problem and also a workaround in Emulate annotation inheritance for interfaces and methods with AspectJ.

Here is a little proof that what you want does not work and thus also cannot be utilised by an aspect:

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

The console output shows that only the inner annotation is seen by the JVM, not the outer one used on the inner annotation:

@de.scrum_master.app.InnerAnnotation()

Update: Intrigued by Bradley M Handy's answer, I re-checked if it would also work for the situation described in my code, and indeed it does. Thise type of AspectJ syntax was unknown to me, even though I think I know a lot about AspectJ. So thanks, Bradley. :-) This aspect would work:

package de.scrum_master.aspect;

import de.scrum_master.app.OuterAnnotation;

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

Console log when running the application:

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



回答2:


I had this exact need in an application. I found this answer, but wasn't satisfied this couldn't be done.

After a bit more searching, I found this cheat sheet for AspectJ/Spring pointcut expressions. The solution in the cheat sheet didn't work exactly as advertised, but I was able to make it work for what I needed.

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

I combined this expression with a @within expression for just the @Annotation to get what I wanted to work.

For method execution:

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

I combined this expression with a @annotation expression for just the @Annotation to get what I wanted to work for methods.



来源:https://stackoverflow.com/questions/31440131/spring-aop-point-cut-for-nested-annotation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!