Spring AOP中如何拦截元注解(注解) [英] How to intercept meta annotations (annotated annotations) in Spring AOP

查看:45
本文介绍了Spring AOP中如何拦截元注解(注解)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我想找到所有用@Controller 注释的类,我会创建这个切入点:

Suppose I want to find all classes annotated with @Controller, I would create this pointcut:

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

但是找不到那些带有@RestController 注解的控制器.由于 RestController 本身带有 @Controller 注释.

But those controllers annotated with @RestController can not be found. Since RestController itself is annoatated with @Controller.

知道如何在不创建两个切入点的情况下找到使用@Controller 或@RestController 注释的类吗?

Any idea on how to find classes annotated either with @Controller or @RestController without having to create two Pointcuts ?

===== 编辑 ====我在这里的真正意图如下:

===== edit ==== My real intention here is as follows:

父注释:

public @interface ParentAnnotation {}

子注解(用@ParentAnnotation注解):

child annotation (annotated with @ParentAnnotation):

@ParentAnnotation 
public @interface ChildAnnotation {}

A 类:

@ParentAnnotation 
public class MyClassA {}

B 类:

@ChildAnnotation 
public class MyClassB {}

现在我想通过@ParentAnnotation 找到 MyClassA 和 MyClassB.找MyClassA是没有问题的,但是MyClassB被@ParentAnnotation间接注解了,有没有通用的方法来处理这种情况?

Now I want to find both MyClassA and MyClassB through @ParentAnnotation. There's no question for finding MyClassA, but MyClassB is indirectly annotated with @ParentAnnotation, is there a generic way to deal such situation?

推荐答案

这个怎么样?

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

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

Or a little shorter, but maybe too fuzzy if there are other classes with matching names in Springs' packages (I have not checked):

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

<小时>

更新:至于你真正的问题,经过你的修改,我现在明白了.这也是可能的,但在语法上有点棘手.让我将您的注释重命名为 MetaAnnotationMyAnnotation,好吗?因为它们并不是真正的父子关系,所以没有 OOP 意义上的继承,只是嵌套.


Update: As for your real question, I understand it now after your edit. This is also possible, but kind of tricky syntactically. Let me rename your annotations into MetaAnnotation and MyAnnotation, okay? Because they are not really parent and child of each other, there is no inheritance involved in the the OOP sense, just nesting.

注释:

请确保注释确实具有运行时范围.我在你的代码中没有看到.

Please make sure that the annotations have indeed runtime scope. I did not see that in your code.

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 示例类:

一个类用元注释注释,一个用带注释的注释,一个没有注释(否定测试用例):

One class is annotated with the meta annotation, one with the annotated annotation and one with no annotation (negative test case):

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

驱动程序应用:

因为我使用的是没有 Spring 的纯 Java + AspectJ,所以我使用这个小应用程序来演示结果.

Because I am using pure Java + AspectJ without Spring, I am using this little application in order to demonstrate the result.

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())

现在,如果您想添加另一层嵌套,请添加一个新注释并用它注释以前未注释的类:

Now if you want to add yet another level of nesting, add a new annotation and annotate the formerly unannotated class with it:

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

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

Then extend the pointcut by one more level of nesting/recursion:

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.:execution(* *(..)) 部分仅在 AspectJ 中是必需的,以便限制切入点匹配到方法执行,因为 AspectJ 可以拦截比 Spring AOP 更多的事件.因此,在 Spring AOP 中,您可以消除该部分以及 ... || 周围的大括号.... ||... 部分.

P.S.: The execution(* *(..)) part is only necessary in AspectJ in order to limit pointcut matching to method executions because AspectJ can intercept more events than Spring AOP. So in Spring AOP you can eliminate that part and the braces surrounding the ... || ... || ... part.

这篇关于Spring AOP中如何拦截元注解(注解)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆