如何使用带注释的参数将参数传递给 Spring AOP 建议? [英] How do I pass arguments to Spring AOP advice with annotated parameters?
问题描述
我将 Spring 3.1.2.RELEASE 与 cglib 加载时编织一起使用,并且我正在尝试获得使用具有自定义注释和带注释参数的方法的建议.
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.
建议:
@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...
}
}
问题是我无法获得执行的建议.如果我删除切入点中的 @args 和 args 条件,则会触发建议,但随后我必须深入研究 ProceedingJoinPoint 以获取我需要的参数.
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.
为什么建议没有触发?我做错了什么吗?
Why isn't the advice firing? Did I do something wrong?
编辑:以下切入点可以作为独立程序与 Spring 一起使用:
Edit: The following pointcut DOES WORK as a standalone program with 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();
}
}
但是,它在使用加载时编织的 JBoss 6 下不起作用.那么,我想我的问题应该是,为什么它可以作为独立程序运行,而不能在 JBoss 6 下运行?
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?
推荐答案
更新: 我忘了提到 @args()
不是为了匹配参数的注释,而是一个参数类型的注解,这不是你想要的,所以我在这里不使用.
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()
绑定参数的注解,只能绑定参数本身.这意味着您只能通过反射访问参数的注释.您需要确定方法签名,从中创建一个 Method
对象,然后迭代方法参数的注释.这是一个完整的代码示例:
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 Method
object from it and then iterate over the method parameters' annotations. Here is a full code sample:
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();
}
}
当我运行 UpdateManagerImpl.main
时,我看到以下输出,正如预期的那样:
When I run UpdateManagerImpl.main
, I see the following output, just as expected:
execution(void com.mycompany.UpdateManagerImpl.processUpdate(MyBatchObject))
com.mycompany.MyBatchObject@86f241
lockValue
Processing update
免责声明:我不是 Spring 专家,我只是用普通的 AspectJ 测试了这个,而不是 Spring AOP.
Disclaimer: I am not a Spring guy, I just tested this with plain AspectJ, not Spring AOP.
这篇关于如何使用带注释的参数将参数传递给 Spring AOP 建议?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!