如何在springaop中截取元注解(annotated annotations)

ztmd8pv5  于 2021-07-15  发布在  Java
关注(0)|答案(1)|浏览(370)

假设我想找到用@controller注解的所有类,我将创建以下切入点:

@Pointcut("within(@org.springframework.stereotype.Controller *)")
    public void controllerPointcut() {}

但是找不到那些用@restcontroller注解的控制器。因为restcontroller本身是用@controller注解的。
你知道如何找到用@controller或@restcontroller注解的类而不必创建两个切入点吗?
=====编辑===我的真实意图如下:
父注解:

public @interface ParentAnnotation {}

子注解(用@parentannotation注解):

@ParentAnnotation 
public @interface ChildAnnotation {}

a类:

@ParentAnnotation 
public class MyClassA {}

b类:

@ChildAnnotation 
public class MyClassB {}

现在我想通过@parentannotation找到myclassa和myclassb。查找myclassa毫无疑问,但是myclassb是用@parentannotation间接注解的,有没有通用的方法来处理这种情况?

e4yzc0pl

e4yzc0pl1#

这个怎么样?

@Pointcut(
  "within(@org.springframework.stereotype.Controller *) || " + 
  "within(@org.springframework.web.bind.annotation.RestController *)" + 
)

或者稍微短一点,但如果springs的包中有其他具有匹配名称的类(我没有检查),则可能太模糊了:

@Pointcut("within(@(org.springframework..*Controller) *)")

更新:至于你真正的问题,我现在理解你的编辑后。这也是可能的,但在句法上有点棘手。让我将您的注解重命名为 MetaAnnotation 以及 MyAnnotation ,好吗?因为它们实际上不是彼此的父级和子级,所以oop意义上不涉及继承,只是嵌套。
注解:
请确保注解确实具有运行时范围。我在你的代码里没看到。

package de.scrum_master.app;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target({ TYPE })
public @interface MetaAnnotation {}
package de.scrum_master.app;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target({ TYPE })
@MetaAnnotation
public @interface MyAnnotation {}

java示例类:
一个类用元注解注解,一个带注解,一个不带注解(否定测试用例):

package de.scrum_master.app;

@MetaAnnotation
public class MyClassA {
  public void doSomething() {}
}
package de.scrum_master.app;

@MyAnnotation
public class MyClassB {
  public void doSomething() {}
}
package de.scrum_master.app;

public class MyClassC {
  public void doSomething() {}
}

驱动程序应用程序:
因为我使用的是纯java+aspectj,没有spring,所以我使用这个小应用程序来演示结果。

package de.scrum_master.app;

public class Application {
  public static void main(String[] args) {
    new MyClassA().doSomething();
    new MyClassB().doSomething();
    new MyClassC().doSomething();
  }
}

外观:

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 MetaAnnotationInterceptor {
  @Before(
    "execution(* *(..)) && (" +
      "within(@de.scrum_master.app.MetaAnnotation *) || " +
      "within(@(@de.scrum_master.app.MetaAnnotation *) *)" +
    ")"
  )
  public void myAdvice(JoinPoint thisJoinPoint){
    System.out.println(thisJoinPoint);
  }
}

控制台日志:

execution(void de.scrum_master.app.MyClassA.doSomething())
execution(void de.scrum_master.app.MyClassB.doSomething())

现在,如果要添加另一个嵌套级别,请添加一个新注解并用它注解以前未注解的类:

package de.scrum_master.app;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target({ TYPE })
@MyAnnotation
public @interface MyOtherAnnotation {}
package de.scrum_master.app;

@MyOtherAnnotation
public class MyClassC {
  public void doSomething() {}
}

然后将切入点再扩展一级嵌套/递归:

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 MetaAnnotationInterceptor {
  @Before(
    "execution(* *(..)) && (" +
      "within(@de.scrum_master.app.MetaAnnotation *) || " +
      "within(@(@de.scrum_master.app.MetaAnnotation *) *) || " +
      "within(@(@(@de.scrum_master.app.MetaAnnotation *) *) *)" +
    ")"
  )
  public void myAdvice(JoinPoint thisJoinPoint){
    System.out.println(thisJoinPoint);
  }
}

控制台日志更改为:

execution(void de.scrum_master.app.MyClassA.doSomething())
execution(void de.scrum_master.app.MyClassB.doSomething())
execution(void de.scrum_master.app.MyClassC.doSomething())

p、 s.:the execution(* *(..)) 只有在aspectj中,为了将切入点匹配限制为方法执行,部分才是必需的,因为aspectj可以截获比SpringAOP更多的事件。因此,在springaop中,您可以消除该部分和围绕 ... || ... || ... 部分。

相关问题