问题描述
我在使用 SpringAOP + AspectJ 设置日志记录方面时遇到了一些麻烦.当使用@Loggable 注释对类或方法进行注释时,我希望触发Around"方法.以下是我的建议代码:
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 和 test2 着火.test3 没有,这是我真正想要的.关于为什么会这样的任何想法?
test1 and test2 fire. test3 does not, and it's the one that I really want. Any thoughts on why this might be?
推荐答案
首先,您的切入点存在语法错误.它不是小写的 argnames
而是 argNames
并且您在参数名称和值之间缺少 =
.所以它必须是 argNames = "bean, loggable"
.
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"
.
其次,如果您的通知返回 void
,它也只会匹配返回 void
的方法.更一般的情况是在通知中返回 Object
以真正匹配所有方法.
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.
最后但并非最不重要的一点是,您应该会看到一个警告,该警告解释了第三个切入点的问题.这会显示在您的 Eclipse IDE 或 AspectJ 编译器 (ajc) 的日志输出中:
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
这意味着您不能说将一个或另一个值绑定到参数 'loggable'".如果两个条件都匹配呢?应该分配哪一个?您有两种选择,假设您的完全限定类名称是 de.scrum_master.app.Loggable
:
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) 不需要引用 @Loggable
注释:
A) No reference to @Loggable
annotation needed:
这是简单的情况.如果@Loggable
没有需要读取的参数,则不需要绑定参数.顺便说一句,如果您希望切入点也捕获静态方法,则不应绑定 target()
,因为目标将为 null
.也许在 Spring-AOP 中这无关紧要,因为它无论如何只能与 Spring Beans 一起使用,但在功能齐全的 AspectJ 中它会有所作为,因为它更强大.
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();
}
或者,等效地:
@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) 需要引用 @Loggable
注释:
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.
这篇关于AspectJ OR 运算符似乎不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!