web-dev-qa-db-ja.com

注釈付きパラメーターを使用してSpringAOPアドバイスに引数を渡すにはどうすればよいですか?

Spring 3.1.2.RELEASEをcglibロードタイムウィービングで使用しており、カスタムアノテーションとアノテーション付きパラメーターを持つメソッドを使用するためのアドバイスを得ようとしています。

助言:

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

ただし、ロード時ウィービングを使用するJBoss6では機能しません。それでは、なぜそれがスタンドアロンプ​​ログラムとして機能するのに、JBoss 6では機能しないのかという質問があると思います。

8
Brad

更新:@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の人ではありません。これは、SpringAOPではなくプレーンなAspectJでテストしただけです。

2
kriegaex

これは解決策ではありませんが、さらに一歩進む必要があります。

注釈にタイプミスをしたと思いますが、おそらく@Aspectではなく@Adviceを意味していましたか?

私が持っている提案は、これらを試してみることです:

a。名前付きのポイントカットと、ポイントカットに適用するアドバイスに分けます。

@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。これで問題が絞り込まれない場合は、もう1つのオプションとして、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){}
1
Biju Kunjummen