11

メソッドの引数を変更する 2 つの側面があります。両方の側面が同じメソッドに適用される場合、側面の実行が連鎖することを期待し、最初の側面で変更された引数が 2 番目の側面で使用できることを期待します。joinPoint.getArgs();しかし、各側面は元の引数; 2 番目の側面では、変更された値は表示されません。私は例を考案しました:

テストクラス:

public class AspectTest extends TestCase {
    @Moo
    private void foo(String boo, String foo) {
        System.out.println(boo + foo);
    }

    public void testAspect() {
        foo("You should", " never see this");
    }
}

メソッド foo() は、次の 2 つの側面から推奨されます。

@Aspect
public class MooImpl {

    @Pointcut("execution(@Moo * *(..))")
    public void methodPointcut() {}

    @Around("methodPointcut()")
    public Object afterMethodInControllerClass(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("MooImpl is being called");
        Object[] args = joinPoint.getArgs();
        args[0] = "don't";
        return joinPoint.proceed(args);
    }
}

と...

@Aspect
public class DoubleMooImpl {

    @Pointcut("execution(@Moo * *(..))")
    public void methodPointcut() {}

    @Around("methodPointcut()")
    public Object afterMethodInControllerClass(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("DoubleMooImpl is being called");
        Object[] args = joinPoint.getArgs();
        args[1] = " run and hide";
        return joinPoint.proceed(args);
    }
}

出力は次のようになると思います。

MooImpl is being called
DoubleMooImpl is being called
don't run and hide

...しかし、次のとおりです。

MooImpl is being called
DoubleMooImpl is being called
You should run and hide

アドバイスを介して引数を変更するために正しいアプローチを使用していますか?

4

2 に答える 2

3

何日も旅を続けた後、ようやくこのことについて考え、あなたの質問に答えることができました. @AspectJ 表記に慣れていないので、ネイティブの AspectJ 構文を使用しても問題ないことを願っています。

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Moo {}
public class AspectTest {
    @Moo
    private void foo(String boo, String foo) {
        System.out.println(boo + foo);
    }

    public static void main(String[] args) {
        new AspectTest().foo("You should", " never see this");
    }
}
public aspect MooImpl {
    pointcut methodPointcut() : execution(@Moo * *(String, ..));

    Object around(String firstArg) : methodPointcut() && args(firstArg, ..) {
        System.out.println("MooImpl is being called");
        return proceed("don't");
    }
}
public aspect DoubleMooImpl {
    pointcut methodPointcut() : execution(@Moo * *(*, String, ..));

    Object around(String secondArg) : methodPointcut() && args(*, secondArg, ..) {
        System.out.println("DoubleMooImpl is being called");
        return proceed(" run and hide");
    }
}

あなたの間違いはgetArgs()、 を介して取得した引数を操作できると想定したことでした。これは間違っています。に引数を渡すには、上で説明proceed()した を介してそれらを参照する必要がありますargs()。2 つの側面で、最初の文字列引数と 2 番目の文字列引数を取得するための構文に注意してください。

これで問題が解決するはずです。

于 2012-10-26T10:07:37.007 に答える
2

これはアスペクトの順序付けの問題のようには聞こえません。メソッドの引数が Java でどのように処理されるかということです。引数への参照は、最初の引数が文字列であるため、文字列参照が指しているものを変更することによって値によって渡されます何らかの方法で元の文字列に実際に影響を与えるため、そのまま渡されます。

代わりに StringBuilder またはその他の変更可能な型を渡してから状態を変更してみると、状態の変更が正しく反映されるはずです。

アップデート:

可変型でテストしたところ、期待どおりに変更されました。

@Moo
private void foo(StringBuilder boo, StringBuilder foo) {
    System.out.println(boo.toString() + foo.toString());
}

public void testAspect() {
    foo(new StringBuilder("You should"), new StringBuilder(" never see this"));
}

MooImpl アスペクトを使用:

@Aspect
public class MooImpl {

    @Pointcut("execution(@Moo * *(..))")
    public void methodPointcut() {}

    @Around("methodPointcut()")
    public Object afterMethodInControllerClass(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("MooImpl is being called");
        Object[] args = joinPoint.getArgs();
        ((StringBuilder)args[0]).append("****");
        return joinPoint.proceed(args);
    }
}

と DoubleMooImpl:

@Aspect
public class DoubleMooImpl {

    @Pointcut("execution(@Moo * *(..))")
    public void methodPointcut() {}

    @Around("methodPointcut()")
    public Object afterMethodInControllerClass(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("DoubleMooImpl is being called");
        Object[] args = joinPoint.getArgs();
        ((StringBuilder)args[1]).append("****");
        return joinPoint.proceed(args);
    }
}

そしてこの出力を得る:

MooImpl is being called
DoubleMooImpl is being called
You should**** never see this****
于 2012-10-11T19:35:22.497 に答える