Перехватывать аннотированные классы и методы в Spring AOP или AspectJ - PullRequest
1 голос
/ 05 июня 2019

Итак, у меня есть пользовательская аннотация

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Intercepted {}

, которую я хочу использовать для объединения аспектов в методы (AspectJ, @annotation(Intercepted)).

Идея состоит в том, что я создаю аспекткогда я аннотирую метод @Intercepted напрямую - эта часть работает - или если я аннотирую класс, аспект должен быть сплетен во все его (публичные) методы - эта часть не работает.

Кроме того, если я аннотирую класс и одним из его методов, аспект должен быть сплетен только один раз, аннотация уровня метода переопределяет класс уровня один.

По сути, я хочу«добавить аннотацию на уровне класса, если есть аннотация на уровне класса, но только если еще нет аннотации на уровне метода».

Как мне это сделать?

1 Ответ

0 голосов
/ 11 июня 2019

Вот пример AspectJ.Синтаксис pointcut в Spring AOP такой же.

Вспомогательные классы:

package de.scrum_master.app;

import java.lang.annotation.*;

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

@Intercepted
public class AnnotatedClass {
  public void doSomething() {}
  public void doSomethingElse() {}
}
package de.scrum_master.app;

public class AnnotatedMethod {
  @Intercepted
  public void doSomething() {}
  public void doSomethingElse() {}
}
package de.scrum_master.app;

@Intercepted
public class AnnotatedMixed {
  @Intercepted
  public void doSomething() {}
  public void doSomethingElse() {}
}

Приложение драйвера (JavaSE, нет Spring):

package de.scrum_master.app;

public class Application {
  public static void main(String[] args) {
    // Should be logged
    new AnnotatedClass().doSomething();
    // Should be logged
    new AnnotatedClass().doSomethingElse();

    // Should be logged
    new AnnotatedMethod().doSomething();
    // Should NOT be logged
    new AnnotatedMethod().doSomethingElse();

    // Should be logged, but only once
    new AnnotatedMixed().doSomething();
    // Should be logged
    new AnnotatedMixed().doSomethingElse();
  }
}

Формат:

Обратите внимание, что часть execution(* *(..)) && не требуется в Spring AOP, поскольку выполняется только методТочки соединения поддерживаются там.Точка отсечения может быть просто annotatedMethod() || annotatedClass() там.В AspectJ я должен быть более точным, потому что в противном случае были бы зарегистрированы другие типы точек соединения.

package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class AnnotationInterceptor {
  @Pointcut("@annotation(de.scrum_master.app.Intercepted)")
  public void annotatedMethod() {}

  @Pointcut("@within(de.scrum_master.app.Intercepted)")
  public void annotatedClass() {}

  @Before("execution(* *(..)) && (annotatedMethod() || annotatedClass())")
  public void log(JoinPoint thisJoinPoint) {
    System.out.println(thisJoinPoint);
  }
}

Журнал консоли:

execution(void de.scrum_master.app.AnnotatedClass.doSomething())
execution(void de.scrum_master.app.AnnotatedClass.doSomethingElse())
execution(void de.scrum_master.app.AnnotatedMethod.doSomething())
execution(void de.scrum_master.app.AnnotatedMixed.doSomething())
execution(void de.scrum_master.app.AnnotatedMixed.doSomethingElse())
...