如何使用带注释的参数将参数传递给 Spring AOP 建议?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16617374/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I pass arguments to Spring AOP advice with annotated parameters?
提问by Brad
I am using Spring 3.1.2.RELEASE with cglib load-time weaving and I am trying to get advice to work with a method that has custom annotations and annotated parameters.
我正在将 Spring 3.1.2.RELEASE 与 cglib 加载时编织一起使用,并且我正在尝试获得使用具有自定义注释和带注释参数的方法的建议。
Advice:
建议:
@Aspect
public class MyAdvice
{
@Around("execution(@com.mycompany.locking.Lock * *(@com.mycompany.locking.LockVal(*), ..)) " +
"&& args(batch) && @args(propertyToLock)"
public Object lockAndProceed(ProceedingJoinPoint pjp, Object batch, LockVal propertyToLock) throws Throwable {
//Do stuff....
pjp.proceed();
}
}
Here is the class that I am testing:
这是我正在测试的课程:
public interface UpdateManager
{
public void processUpdate(MyBatchObject batch);
}
public class UpdateManagerImpl implements UpdateManager
{
@Lock
public void processUpdate(@LockVal("lockValue") MyBatchObject batch)
{
//Do stuff...
}
}
The problem is that I can't get the advice to execute. If I remove the @args and args conditions in the pointcut, the advice fires, but then I have to dig through the ProceedingJoinPoint to get the parameter that I need.
问题是我无法得到执行的建议。如果我删除切入点中的 @args 和 args 条件,则建议会触发,但随后我必须深入研究 ProceedingJoinPoint 以获取我需要的参数。
Why isn't the advice firing? Did I do something wrong?
为什么建议没有触发?我做错什么了吗?
Edit: The following pointcut DOES WORK as a standalone program with Spring:
编辑:以下切入点可以作为独立程序与 Spring 一起使用:
@Aspect
public class MyAdvice
{
@Around("execution(@com.mycompany.locking.Lock * *(@com.mycompany.locking.LockVal(*), ..)) " +
"&& args(batch)"
public Object lockAndProceed(ProceedingJoinPoint pjp, Object batch) throws Throwable {
//Do stuff....
pjp.proceed();
}
}
However, it does NOT work under JBoss 6 using load-time weaving. I suppose my question should be, then, why does it work as a standalone program but not under JBoss 6?
但是,它在使用加载时编织的 JBoss 6 下不起作用。我想我的问题应该是,为什么它可以作为独立程序运行,但不能在 JBoss 6 下运行?
回答by kriegaex
Update:I forgot to mention that @args()is not meant to match a parameter's annotation, but a parameter type's annotation, which is not what you want and which thus I do not use here.
更新:我忘了提到这@args()不是为了匹配参数的注释,而是参数类型的注释,这不是你想要的,因此我在这里不使用。
You cannot bind a parameter's annotation via args(), only the parameter itself. This means that you can only access the parameter's annotation via reflection. You need to determine the method signature, create a Methodobject from it and then iterate over the method parameters' annotations. Here is a full code sample:
您不能通过 绑定参数的注释args(),只能通过参数本身。这意味着您只能通过反射访问参数的注释。您需要确定方法签名,Method从中创建一个对象,然后迭代方法参数的注释。这是一个完整的代码示例:
package com.mycompany.locking;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Lock {}
package com.mycompany.locking;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface LockVal {
String value() default "";
}
package com.mycompany;
public class MyBatchObject {}
package com.mycompany;
public interface UpdateManager {
public void processUpdate(MyBatchObject batch);
}
package com.mycompany;
import com.mycompany.locking.Lock;
import com.mycompany.locking.LockVal;
public class UpdateManagerImpl implements UpdateManager {
@Lock
@Override
public void processUpdate(@LockVal("lockValue") MyBatchObject batch) {
System.out.println("Processing update");
}
public static void main(String[] args) {
UpdateManager updateManager = new UpdateManagerImpl();
updateManager.processUpdate(new MyBatchObject());
}
}
package com.mycompany.aop;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import com.mycompany.MyBatchObject;
import com.mycompany.locking.LockVal;
@Aspect
public class MyAspect {
@Pointcut("execution(@com.mycompany.locking.Lock * *(@com.mycompany.locking.LockVal (*), ..)) && args(batch)")
public void lockedMethod(MyBatchObject batch) {}
@Around("lockedMethod(batch)")
public Object lockAndProceed(ProceedingJoinPoint pjp, MyBatchObject batch) throws Throwable {
System.out.println(pjp);
System.out.println(batch);
MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
Class<?> clazz = methodSignature.getDeclaringType();
Method method = clazz.getDeclaredMethod(methodSignature.getName(), methodSignature.getParameterTypes());
LockVal propertyToLock;
for (Annotation ann : method.getParameterAnnotations()[0]) {
if(LockVal.class.isInstance(ann)) {
propertyToLock = (LockVal) ann;
System.out.println(propertyToLock.value());
}
}
return pjp.proceed();
}
}
When I run UpdateManagerImpl.main, I see the following output, just as expected:
当我运行时UpdateManagerImpl.main,我看到以下输出,正如预期的那样:
execution(void com.mycompany.UpdateManagerImpl.processUpdate(MyBatchObject))
com.mycompany.MyBatchObject@86f241
lockValue
Processing update
Disclaimer:I am not a Spring guy, I just tested this with plain AspectJ, not Spring AOP.
免责声明:我不是 Spring 专家,我只是用普通的 AspectJ 测试了这个,而不是 Spring AOP。
回答by Biju Kunjummen
This is not a solution, but should take you a step further:
这不是解决方案,但应该让您更进一步:
I am assuming you made a typo in your annotations, you probably meant @Aspectand not @Advice?
我假设您在注释中打错了字,您的意思可能是@Aspect而不是@Advice?
The suggestion that I have would be to try out these:
我的建议是尝试这些:
a. Separate out into named point cuts and the advice that you want to apply on the pointcut:
一种。分离成命名的切入点和要应用到切入点的建议:
@PointCut("execution(@com.mycompany.locking.Lock * *(@com.mycompany.locking.LockVal(*), ..)) && args(batch) && @args(propertyToLock)")
public void mypointcut(Object batch, LockVal propertyToLock){}
@Around("mypointcut(batch, propertyToLock)"
public Object lockAndProceed(ProceedingJoinPoint pjp, Object batch, LockVal propertyToLock) throws Throwable {
//Do stuff....
pjp.proceed();
}
b. It could be that either argsexpression or @argsexpression is causing the issue - try keeping one and removing other and seeing which combination works.
湾 可能是args表达式或@args表达式导致了问题 - 尝试保留一个并删除另一个并查看哪种组合有效。
c. If this does not narrow things down, one more option could be to explicitly add an argNamesexpression also, it could be that the argument names are being cleaned out and not being matched up by name at runtime:
C。如果这不能缩小范围,另一种选择可能是显式添加argNames表达式,也可能是参数名称被清除并且在运行时未按名称匹配:
@PointCut("execution(@com.mycompany.locking.Lock * *(@com.mycompany.locking.LockVal(*), ..)) && args(batch) && @args(propertyToLock) && argNames="batch,test1,test2")
public void mypointcut(Object batch, LockVal propertyToLock){}

