私はクラスを持っています:
class MyClass {
@MyAnnotation
public void someMethod() {
}
}
ポイントカットのアドバイスでは、基本的にアノテーションの対象となる「メソッド」を抽出しています。次に、いくつかの構成に応じて、メソッドは多くのハンドラーの 1 つに委任されます。
ここで指摘しなければならないのは、すべての問題の原因はjoinPoint.proceed()
、アドバイスを実際に実行できないことにあるということです。Method.invoke()
並列スレッドでそのメソッドを呼び出し続ける別のデリゲートがあり、その実行にはProceedingJoinPoint
.
問題は、Method.invoke()
onを実行するたびにsomeMethod
、(もちろん) アドバイスが再度実行されることです。これは、注釈が付けられているためです。これにより、何度も何度も実行されます。
次のいずれかに行く必要があります。
- リフレクションまたは Method.invoke によって呼び出された場合は、アドバイスを実行しないでください (実際には可能だとは思いません)。
- 呼び出しがデリゲートの 1 つからのものであるかどうかを、アドバイス内で検出します。
#2 については、フラグか何かを設定することを検討しましたが、それではもはやスレッドセーフではありません。
助言がありますか?
より明確なコード例:
私は定義されたアスペクトを持っています:
@Pointcut("execution(@com.rohanprabhu.annotation.Process * *(..)) "
+ "&& @annotation(process)")
public void processPointcut(Process process) {
}
@Around("processPointcut(process)")
public Object process(final ProceedingJoinPoint joinPoint, final Process process)
throws Throwable {
final Object callingObject = joinPoint.getThis();
final Method method = ((MethodSignature)joinPoint.getSignature()).getMethod();
final MethodContext methodContext = new MethodContext(callingObject, method);
//The below mentioned delegate will be picked
//depending on some validation performed on 'callingObject'
Object retValue = delegate.process(methodContext, joinPoint.getArgs());
return retValue;
}
デリゲートは次のようになります。
class SimpleDelegate extends Delegate {
@Override
public Object process(final MethodContext methodContext, final Object[] args) {
// The problem is that following invoke call calls
// the @Around aspect to run again, which calls the delegate again,
// which causes execution of the next line, which causes the aspect to run
// again and so on...
methodContext.getMethod().invoke(
methodContext.getCallingObject(),
args
);
}
}
次のようなことができれば素晴らしいと思います(次のようなものがあるとは本当に思いませんcalledByReflection
:
@Pointcut("execution(@com.rohanprabhu.annotation.Process * *(..)) "
+ "&& @annotation(process)" + " && !calledByReflection")
public void processPointcut(Process process) {
}
または次のようなもの:
@Around("processPointcut(process)")
public Object process(final ProceedingJoinPoint joinPoint, final Process process,
final boolean processAnnotation)
throws Throwable {
if(processAnnotation) {
// Do the regular stuff
}
}
processAnnotation
そして、アスペクトに価値を提供する方法がいくつかありました。これで私の質問が明確になったことを願っています。}