После углубления в топи c АОП я наконец нашел рабочее решение.
Первоначально я использую следующие точки:
@Aspect
@Component
public static class MyAnnotationAspect {
/**
* Matches the execution of any methods in a type annotated with @MyAnnotation.
*/
@Pointcut("execution(* (@com.test.MyAnnotation *).*(..))")
public void methodInMyAnnotationType() {}
/**
* Matches the execution of any methods annotated with @MyAnnotation.
*/
@Pointcut("execution(@com.test.MyAnnotation * *.*(..))")
public void methodAnnotatedWithMyAnnotation() {}
@Around("methodInMyAnnotationType() || methodAnnotatedWithMyAnnotation()")
public Object aop(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("AOP IS WORKING");
return pjp.proceed;
}
}
Что я узнал заключается в том, что methodInMyAnnotationType
pointcut будет работать, только если я добавлю @MyAnnotation
в класс, который фактически владеет методом. Однако, если я добавлю аннотацию к классу B, которая расширяет класс A, AOP не сможет перехватить методы из класса A.
Одно из возможных решений, которое я нашел, заключается в следующем.
@Pointcut("execution(* *(..)) && @this(com.test.MyAnnotation)")
Это означает, что pointcut предназначен для ВСЕХ методов из текущего класса И родительского класса, а текущий класс должен быть помечен @MyAnnotation
. Это выглядит многообещающе. К сожалению, Spring AOP не поддерживает @this
примитив pointcut, который выдает UnsupportedPointcutPrimitiveException
.
. После еще большего изучения топи c из this
я обнаружил существование примитива target
и придумал следующее решение.
@Pointcut("execution(@com.test.MyAnnotation * *.*(..))")
public void annotatedMethod() {}
@Pointcut("execution(* (@com.test.MyAnnotation *).*(..))")
public void annotatedClass() {}
@Pointcut("execution(* *(..)) && target(com.test.MyAnnotable)")
public void implementedInterface() {}
@Around("annotatedMethod() || annotatedClass() || implementedInterface()")
public Object aop(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("AOP IS WORKING");
return pjp.proceed;
}
Это означает, что pointcut предназначен для ВСЕХ методов из текущего класса И родительского класса. Кроме того, метод должен быть аннотирован @MyAnnotation
, или класс, содержащий метод, аннотирован @MyAnnotation
, или объект, имеющий этот метод, должен быть экземпляром интерфейса маркера MyAnnotable
. Это выглядит красиво и работает.
Моя последняя реализация класса выглядит следующим образом.
@Service
public class ShiftModule {
@Service
public class Annotated extends ShiftModule implements MyAnnotable {}
@Resource
private ShiftModule.Annotated self;
}
Информация о дополнении:
Я дал следующая попытка во время моих экспериментов:
@Pointcut("@annotation(com.test.MyAnnotation)")
public void annotatedMethod() {}
@Pointcut("@within(com.test.MyAnnotation)")
public void annotatedClass() {}
@Pointcut("target(com.test.MyAnnotable)")
public void implementedInterface() {}
@Around("execution(* *(..)) && (annotatedMethod() || annotatedClass() || implementedInterface()")
public Object aop(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("AOP IS WORKING");
return pjp.proceed;
}
Я обнаружил, что она НЕ работает с аннотированным внутренним интерфейсом, что означает, что приведенный ниже код перестанет работать. AOP-аспект вообще не имеет никаких эффектов.
@Repository
public interface OrderRepo extends JpaRepository<Order,Long> {
@Repository("annotatedOrderRepo")
@MyAnnotation
public interface Annotated extends OrderRepo {}
}