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

查看:200
本文介绍了如何在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注释的类而无需创建两个Pointcut的任何想法?

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天全站免登陆