2012-10-11 41 views
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 

我使用正確的方法通過各地的意見,修改參數?

+0

請訂閱AspectJ用戶郵件列表並在那裏提出您的問題。你應該在那裏得到一個合格的答案。我也會對結果感興趣。 – kriegaex

回答

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**** 
+0

可變類型與否,行爲是相同的。 –

+0

這是,我只是測試它,更詳細的更新我的答案。在你的情況下,你在修改args [0]或args [1]之前指向正確的對象,但是當你說'args [0] =「不要」時,引用指向一個品牌不同的對象共。你得到的args數組只是參數引用的一個副本,所以改變參數數組實際上沒有任何作用,而如果你改變它的方式,我的樣本中它的確會得到反映。 –

+0

我明白數組是參數的副本。我不明白的是爲什麼這兩個方面中的第二個沒有得到第一方面調用proceed(args)傳遞的參數的副本。 –

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參數的語法。

這應該可以解決您的問題。

+0

使用@AspectJ風格,這意味着你必須使用'ProceedingJointPoint.proceed(Object [] args)'來獲得相同的功能,但語義有點不同,你應該參考[javadoc](http:// www.eclipse.org/aspectj/doc/released/runtime-api/org/aspectj/lang/ProceedingJoinPoint.html)以獲得準確的參數。 –