As you probably have noticed, you cannot bind information from different ||
branches to an advice method parameter because it would be ambiguous, see also my answers here and here. So if you want to avoid ugly (and slow) reflection, do what I recommended in the other answers and write two distinct advices, factoring out the common code into a helper method if avoiding code duplication is your concern here. Something like this (untested, just to give you an idea about the code structure):
@Around("@within(annotation)")
public Object classIsAdmin(ProceedingJoinPoint pjp, IsAdmin annotation) throws Throwable {
return commonIsAdmin(pjp, annotation);
}
@Around("@annotation(annotation)")
public Object methodIsAdmin(ProceedingJoinPoint pjp, IsAdmin annotation) throws Throwable {
return commonIsAdmin(pjp, annotation);
}
public Object commonIsAdmin(ProceedingJoinPoint pjp, IsAdmin annotation) throws Throwable {
// Here you would place all common advice code.
// Non-common code could remain in the original advice methods.
log.info("value->>{}", annotation.value());
return pjp.proceed();
}
why I need to change the response value from void
to Object
and return pjp.proceed()
. If the method do not have response, the request will freezing.
In contrast to a @Before
or @After
advice, in an @Around
advice you can modify the return value by either skipping the target method execution completely by not calling proceed()
or by discarding or modifying the result of proceed()
. You are completely free in what you want to return, it just has to match the target method's return type.
Having said that, it should become clear that an around advice method also must have a return type matching that of the target method(s) it intercepts. It can be an exact type like MyType
, a super type or simply Object
(super type for all types) if your advice targets a multitude of types without a common super type. The advice can also have a return type of void
if (and only if) all target methods also return void
(otherwise the advice just would not match those methods, even if the pointcut as such would match).
So if an around advice matches is determined by a combination of the pointcut itself and the return type. You can use that as a tool to limit pointcut matching by defining a specific return type (to which you then would need to cast the return value of proceed()
because proceed()
always returns an Object
).
BTW, if the target method returns a primitive type like int
, boolean
etc., then the advice would auto-wrap the result to be an Integer
or Boolean
.
You really ought to read Spring AOP and AspectJ manuals or tutorials because I am explaining things here which can be found there.
Update: The OP asked for documentation concerning parameter binding and a description how names are determined:
- You can specify an
argNames
parameter for all advice types, e.g. @Before
, @After
, @Around
.
- If that annotation parameter is absent, Spring AOP will try to match advice method parameter names via class file debug info, if compiled in. Otherwise matching would fail in this case.
- When using full AspectJ with compile-time weaving instead of Spring AOP, determining names also works without debug info because the AspectJ compiler can determine the necessary information during compilation.
All of this is described in the Spring AOP manual.