I want to have annotation on class level that will execute advice on every method in annotated class. Is that even possible.
Example: I would like to annotate OmniDemoService
with @DoSomethingForMe
and I want both method1 and method2
to log " look at me " before execution
This example is not working and I don't know why. When I transform Pointcut to Around and just use it with annotation (also change annotation ElementType to method) everything is working on method level. So I think it is wrong defined Pointcut.
Annotation:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DoSomethingForMe {
}
Advice:
@Aspect
@Component
public class DoSomethingForMeAdvice {
private static final Logger logger = LoggerFactory.getLogger(DoSomethingForMeAdvice.class);
@Pointcut("execution(public * *(..)) && @annotation(DoSomethingForMe)")
public void anyAnnotatedMethod() {
}
@Before("anyAnnotatedMethod()")
public void acquireExecution() {
logger.info("look at me");
}
}
Usage:
@Service
@DoSomethingForMe
public class OmniDemoService {
private static final Logger logger = LoggerFactory.getLogger(OmniDemoService.class);
public void method1() {
logger.info("---1---");
}
public void method2() {
logger.info("---2---");
}
}
Your issue is that you are confusing pointcut definition with advices.
Pointcut is aiming, advice performs the actual WhateverYouWantToBeExecuted. Like for example
@Pointcut("@annotation(com.omnidemo.advice.DoSomethingForMe)")
public void anyAnnotatedMethod() {
}
@Before("anyAnnotatedMethod()")
public void logMethodCall(JoinPoint jp) {
String methodName = jp.getSignature().toShortString();
logger.info("Executing: " + methodName);
}
Check out what the AspectJ quick reference says about @annotation()
:
any join point where the subject has an annotation of type
SomeAnnotation
You used @annotation(DoSomethingForMe)
but the " subject " of a method execution is a method . So that would mean any method annotated @DoSomethingForMe.
Use @this(DoSomethingForMe)
or @target(DoSomethingForMe)
.
Thanks to kriegaex for pointing out that @this
and @target
must be evaluated at runtime, which would pollute the codebase a lot (ie check in every method). So the next approach is better:
If you check the AspectJ manual section about type patterns you will see that you can annotate the type directly. Please also remember to use use fully qualified class names. So that would be:
execution(public * (@com.path.DoSomethingForMe *).*(..))
Also, if you have such a simple pointcut and you don't need to reuse it, I think you can drop the additional method and just use it in the advice directly:
@Before("execution(public * (@com.path.DoSomethingForMe *).*(..))")
which says: "before the execution of any public method of a type annotated with @com.path.DoSomethingForMe
", where "before the execution of a method" means "inside the method, at the beginning".
Alternatively, if this pointcut looks a bit too complicated for you, you can separate annotation matching and method matching like this, as suggested by J Asgarov in his comment:
@Before("execution(public * *(..)) && @within(com.path.DoSomethingForMe)")
Solution for the problem is to use within for pointcut
@Pointcut("@within(DoSomethingForMe)")
public void anyAnnotatedMethod() {
}
@Before("anyAnnotatedMethod()")
public void acquireExecution() {
logger.info("look at me");
}
Solution provided by @J Asgarov in the comments
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.