【问题标题】:How do I pass arguments to Spring AOP advice with annotated parameters?如何使用带注释的参数将参数传递给 Spring AOP 建议?
【发布时间】:2013-05-13 02:43:35
【问题描述】:

我正在使用带有 cglib 加载时编织的 Spring 3.1.2.RELEASE,并且我正在尝试获得使用具有自定义注释和注释参数的方法的建议。

建议:

@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();
   }
}

这是我正在测试的课程:

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 以获取我需要的参数。

为什么建议没有触发?我是不是做错了什么?

编辑:以下切入点可以作为 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 下运行?

【问题讨论】:

  • 我知道这是旧的,但仍列为未答复。如果它看起来合适,请您接受并支持我的回答吗?谢谢。
  • 我现在已经离开了那个项目,但我可以说无论我如何运行它,代码都无法正常工作。我记得,它与 JBoss 6 中的 flat classloader + cglib 有关,这与以前的版本不同。

标签: spring aop aspectj spring-aop


【解决方案1】:

更新:我忘了提到@args() 不是要匹配参数的注释,而是参数类型的注释,这不是你想要的,因此我在这里不使用。


您不能通过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();
    }
}

当我运行UpdateManagerImpl.main 时,正如预期的那样,我看到了以下输出:

execution(void com.mycompany.UpdateManagerImpl.processUpdate(MyBatchObject))
com.mycompany.MyBatchObject@86f241
lockValue
Processing update

免责声明:我不是 Spring 人,我只是用普通的 AspectJ 测试了这个,而不是 Spring AOP。

【讨论】:

  • 请问,@args 是什么意思?我不确定我是否理解参数上的注释和参数类型上的注释之间的区别。
  • 另外,我尝试将@args 完全从切入点中删除,但切入点仍未执行。 args() 条件的某些原因导致它失败,因为当我删除这两个条件时,切入点确实按预期执行。
  • 只需使用我的代码,它就可以工作。至于@args,如果抓到一个参数MyType foo@args只匹配类MyType上声明的注解,而不匹配方法参数上的注解。
  • 我尝试按照您的建议使用此代码,但切入点没有执行。如果我删除 args(batch) 条件,它确实如此。
  • 那你没有使用我所有的代码或者你错误地调整了你的代码。我特意发布了带有注释、导入和包名称的完整示例,因此您可以看到完整的图片。如果你在调整中没有犯任何错误,或者 Spring AOP 和 AspectJ 之间没有根本区别,你应该没问题。
【解决方案2】:

这不是一个解决方案,但应该能让你更进一步:

我假设您在注释中打错字了,您的意思可能是 @Aspect 而不是 @Advice

我的建议是尝试这些:

一个。分离成命名切入点和您要在切入点上应用的建议:

@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.可能是 args 表达式或 @args 表达式导致了问题 - 尝试保留一个并删除另一个并查看哪种组合有效。

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){}

【讨论】:

  • 不能通过args()绑定参数的注解,只能绑定参数本身。请参阅我自己的答案。
  • 我试过 a) 和 b) 都没有成功。我正在测试 c) - 感谢您的建议!
  • 当我尝试切入点时:execute(@com.mycompany.locking.Lock * *(@com.mycompany.locking.LockVal (*))) &amp;&amp; args(batch) &amp;&amp; argNames(\"batch\") 我收到了错误error at ::0 multiple bindings0, BindingTypePattern(java.lang.Object, 0)
猜你喜欢
  • 2018-07-24
  • 1970-01-01
  • 1970-01-01
  • 2018-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多