AspectJ OR Operator Doesn't Seem to be Functioning

谁说我不能喝 提交于 2021-02-05 11:43:41

问题


I'm having a little trouble getting a logging aspect set up using SpringAOP + AspectJ. I would like an "Around" method to fire when either a class or method is annotated with the @Loggable annotation. Below is my advice code:

@Around(value = "execution( * *(..)) && target(bean) && @annotation(loggable)", argnames "bean, loggable")
public void test1(ProceedingJoinPoint method, Object bean, Loggable loggable) { }

@Around(value = "execution( * *(..)) && target(bean) && @within(loggable)", argnames "bean, loggable")
public void test2(ProceedingJoinPoint method, Object bean, Loggable loggable) { }

@Around(value = "execution( * *(..)) && target(bean) && (@annotation(loggable) || @within(loggable))", argnames "bean, loggable")
public void test3(ProceedingJoinPoint method, Object bean, Loggable loggable) { }

test1 and test2 fire. test3 does not, and it's the one that I really want. Any thoughts on why this might be?


回答1:


First of all, there are syntax errors in your pointcuts. It is not lower-case argnames but argNames and you are missing an = in between parameter name and value. So it must be argNames = "bean, loggable".

Secondly if your advice returns void it will only match methods returning void as well. The more general case is to return Object in the advice to really match all methods.

Last but not least, you should see a warning which explains the problem with the third pointcut. This is displayed in your Eclipse IDE or on the AspectJ compiler's (ajc) log output:

ambiguous binding of parameter(s) loggable across '||' in pointcut

This means that you cannot say "bind one value or the other to the parameter 'loggable'". What if both conditions match? Which one should be assigned? You have two options, assuming your fully-qualified class name is de.scrum_master.app.Loggable:

A) No reference to @Loggable annotation needed:

This is the simple case. If @Loggable does not have any parameters you need to read, it is not necessary to bind it to a parameter. BTW, if you want your pointcut to also capture static methods, you should not bind target() either because the target would be null. Maybe in Spring-AOP this is irrelevant because it only works with Spring Beans anyway, but in full-featured AspectJ it would make a difference because it is more powerful.

@Around(value = "execution(* *(..)) && (@annotation(de.scrum_master.app.Loggable) || @within(de.scrum_master.app.Loggable))")
public Object withoutLoggableReference(ProceedingJoinPoint thisJoinPoint) {
    Object bean = thisJoinPoint.getTarget();
    System.out.println(thisJoinPoint + " -> " + bean);
    return thisJoinPoint.proceed();
}

Or, equivalently:

@Around(value = "execution(* (@de.scrum_master.app.Loggable *.*)(..)) || execution(@de.scrum_master.app.Loggable * *.*(..))")
public Object withoutLoggableReference(ProceedingJoinPoint thisJoinPoint) {
    Object bean = thisJoinPoint.getTarget();
    System.out.println(thisJoinPoint + " -> " + bean);
    return thisJoinPoint.proceed();
}

B) Reference to @Loggable annotation needed:

You have no other choice than to go with two separate pointcuts if you want to bind the annotations to parameters. Maybe you could use a utility method doing the actual logging in order to avoid code duplication in your advice.



来源:https://stackoverflow.com/questions/26103519/aspectj-or-operator-doesnt-seem-to-be-functioning

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!