11

我有两个方面,每个方面都修改方法参数。当两个方面都应用于同一个方法时,我希望这些方面的执行被链接起来,并且我希望在第一个方面修改的参数可以通过第二个方面使用joinPoint.getArgs();但是,似乎每个方面只获得原始论点;第二个方面永远不会看到修改后的值。我设计了一个例子:

测试类:

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() 方法有两个方面的建议:

@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(),我在上面已经演示过。请注意在两个方面检索第一个和第二个 String 参数的语法。

这应该可以解决您的问题。

于 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 回答