繁体   English   中英

Spring AOP:有没有一种方法可以使@target用于间接注释?

[英]Spring AOP: is there a way to make @target work for indirect annotations?

我有一个注释:

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
public @interface MyAnnotation {
}

我用它注释Spring MVC控制器:

@MyAnnotation
public class TestController { ... }

然后,我添加一条建议,其中包含以下内容:

@Pointcut("@target(MyAnnotation)")
public void annotatedWithMyAnnotation() {}

@Around("annotatedWithMyAnnotation()")
public Object executeController(ProceedingJoinPoint point) throws Throwable { ... }

建议的方法已成功调用。

现在,我有一堆共享相同注释的控制器,我想使用构造型注释对它们进行分组。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@MyAnnotation
... other annotations
public @interface StereotypeAnnotation {
}

然后用@StereotypeAnnotation注释我的控制器:

@StereotypeAnnotation
public class TestController { ... }

控制器不再直接包含@MyAnnotation

问题是在这种情况下@target切入点停止匹配我的控制器,因此不建议使用它们。

有没有一种方法可以定义一个与具有此类间接注释的控制器匹配的切入点?

我用纯AspectJ重新创建了这种情况,因为我不太喜欢Spring AOP。 这就是为什么我在通知的切入点之前添加了额外的execution(* *(..)) && ,以避免匹配Spring AOP中不可用的其他联接点,例如call() 如果愿意,可以在Spring AOP中将其删除。

好的,让我们根据您的描述创建这种情况:

package de.scrum_master.app;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
public @interface MyAnnotation {}
package de.scrum_master.app;

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

@Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@MyAnnotation
public @interface StereotypeAnnotation {}
package de.scrum_master.app;

@MyAnnotation
public class TestController {
  public void doSomething() {
    System.out.println("Doing something");
  }
}
package de.scrum_master.app;

@StereotypeAnnotation
public class AnotherController {
  public void doSomething() {
    System.out.println("Doing yet another something");
  }
}

这是我们的纯Java驱动程序应用程序(没有Spring):

package de.scrum_master.app;

public class Application {
  public static void main(String[] args) {
    new TestController().doSomething();
    new AnotherController().doSomething();
  }
}

这是方面:

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class MetaAnnotationAspect {
  @Pointcut(
    "@target(de.scrum_master.app.MyAnnotation) || " +
    "@target(de.scrum_master.app.StereotypeAnnotation)"
  )
  public void solutionA() {}

  @Around("execution(* *(..)) && solutionA()")
  public Object executeController(ProceedingJoinPoint point) throws Throwable {
    System.out.println(point);
    return point.proceed();
  }
}

日志输出为:

execution(void de.scrum_master.app.TestController.doSomething())
Doing something
execution(void de.scrum_master.app.AnotherController.doSomething())
Doing yet another something

到现在为止还挺好。 但是,如果我们添加另一层嵌套怎么办?

package de.scrum_master.app;

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

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@StereotypeAnnotation
public @interface SubStereotypeAnnotation {}
package de.scrum_master.app;

@SubStereotypeAnnotation
public class YetAnotherController {
  public void doSomething() {
    System.out.println("Doing another something");
  }
}
package de.scrum_master.app;

public class Application {
  public static void main(String[] args) {
    new TestController().doSomething();
    new AnotherController().doSomething();
    new YetAnotherController().doSomething();
  }
}

然后,切入点将不再匹配嵌套的元/定型注释:

execution(void de.scrum_master.app.TestController.doSomething())
Doing something
execution(void de.scrum_master.app.AnotherController.doSomething())
Doing yet another something
Doing another something

我们将必须显式添加|| @target(de.scrum_master.app.StereotypeAnnotation) || @target(de.scrum_master.app.StereotypeAnnotation)指向切入点,即我们必须知道层次结构中的所有注释类名称。 有一种方法可以使用一个特殊的语法来解决within()切入点指示符,也可以在这里查看我的其他答案

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class MetaAnnotationAspect {
  @Pointcut(
    "within(@de.scrum_master.app.MyAnnotation *) || " +
    "within(@(@de.scrum_master.app.MyAnnotation *) *) || " +
    "within(@(@(@de.scrum_master.app.MyAnnotation *) *) *)"
  )
  public void solutionB() {}

  @Around("execution(* *(..)) && solutionB()")
  public Object executeController(ProceedingJoinPoint point) throws Throwable {
    System.out.println(point);
    return point.proceed();
  }
}

控制台日志更改为:

execution(void de.scrum_master.app.TestController.doSomething())
Doing something
execution(void de.scrum_master.app.AnotherController.doSomething())
Doing yet another something
execution(void de.scrum_master.app.YetAnotherController.doSomething())
Doing another something

看到? 我们只需要知道一个注释类,即MyAnnotation ,即可覆盖元注释的两个嵌套级别。 添加更多级别将很简单。 我承认这种注解嵌套似乎是人为设计的,我只是想向您解释您拥有哪些选项。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM