我有两个方面,每个方面修改方法参数。当两个方面都应用于同一个方法时,我希望链接的方面的执行被链接,我希望第一个方面中修改的参数可以通过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
我是否使用正确的方法通过建议来修改参数?
答案 0 :(得分: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参数的语法。
这可以解决您的问题。
答案 1 :(得分:2)
这听起来不像是一个方面排序问题,它更多的是如何在java中处理方法参数 - 对参数的引用是按值传递的,因为你的第一个参数是一个String,通过修改String引用指向的内容你并没有真正以任何方式影响原始的字符串,所以就这样传递。
您可以尝试传入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:
@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****