2014-04-29 34 views
1

我無法在其中一個參數是可變參數時使spring-AOP切入點工作。鑑於下面的代碼,我會希望在我的測試中的兩個調用都會觸發切入點,但在任何情況下都不會調用它。我有其他方面的工作在同一個類的其他方法,所以我知道這不是我的測試或彈簧設置的問題 - 它似乎與這種方法是孤立的,唯一獨特的是可變參數。彈簧AOP切入點不能與可變參數一起使用

方法聲明:

SearchResults getRelation(final ClmUserContextFactory contextFactory, final CloudObjectId objectId, 
      final Class<? extends CloudClass>... relationClasses) throws BmcClientException; 

切入點聲明:

@Around(value = "execution(com.a.b.SearchResults " 
     + "com.a.b.BmcClmRestJsonClient.getRelation(com.a.b.ClmUserContextFactory, com.a.b.CloudObjectId, Class<? extends com.a.b.CloudClass>...))" 
     + " && args(contextFactory, objectId, relationClasses)", 
     argNames = "jp,contextFactory,objectId,relationClasses") 
private SearchResults getRelationVarargs(ProceedingJoinPoint jp, ClmUserContextFactory contextFactory, 
     CloudObjectId objectId, 
     Class<? extends CloudClass>[] relationClasses) 
     throws Throwable 
{...} 

呼叫從測試:

bmcClmRestJsonClient.getRelation(contextFactory, objectId, new Class[] { CloudClass.class }); 

bmcClmRestJsonClient.getRelation(contextFactory, objectId); 

編輯:

我可以證實,如果我刪除可變參數p定義的藝術(即刪除切入點和方法定義的所有'...'和'[]'),所以它絕對看起來與這些有關。如果我用'[]'替換'...',它也不起作用。

+0

不用擔心。我剛刪除它 – JamesENL

+0

此問題仍列爲未答覆。如果看起來合適,請您接受並提出我的答案嗎?謝謝。 – kriegaex

+0

我很欣賞你的評論,並且贊成它(因爲它有幫助),但是因爲它沒有解決爲什麼它不能在春季運行的核心問題 - 我不能接受它作爲一個完整的答案。我認爲這個問題仍然沒有答案。 – chesterm8

回答

0

雖然我還沒有找到解決方案,但有一個解決方法 - 您可以從連接點獲取參數。下面是我自己的決定:

@Around(value = "execution(com.a.b.SearchResults " 
     + "com.a.b.BmcClmRestJsonClient.getRelation(*, *, ..))") 
public SearchResults getRelationVarargs(ProceedingJoinPoint jp) 

我提取連接點的參數如下:

Object[] args = jp.getArgs(); 

ClmUserContextFactory contextFactory = (ClmUserContextFactory) args[0]; 
CloudObjectId objectId = (CloudObjectId) args[1]; 
Class<? extends CloudClass>[] relationClasses = null; 
if (args.length == 3) 
{ 
    relationClasses = (Class<? extends CloudClass>[]) args[2]; 
} 

這顯然是不夠好,如果你需要指定的參數切入點是爲了讓它切入正確的位置 - 幸運的是,對於我來說並非如此。

1

我不是一個Spring用戶,但我用AspectJ嘗試了這一點,都使用代碼風格和註釋風格的語法。對我來說它是有效的,所以我認爲它應該也適用於你,如果你的切入點定義是正確的。

更新:我也認爲你的建議方法必須是公開的,而不是私人的。

樣品驅動器應用:

package de.scrum_master.app; 

public class Application { 
    public static void main(String[] args) { 
     System.out.println("Starting application"); 
     doSomething(11, String.class, String.class); 
     System.out.println("Stopping application"); 
    } 

    public static boolean doSomething(final int number, final Class<? extends String>... classes) { 
     System.out.println("Doing something"); 
     return true; 
    } 
} 

代碼風格方面:

package de.scrum_master.aspect; 

import de.scrum_master.app.Application; 

public aspect CodeStyleAspect { 
    boolean around(int number, Class<? extends String>[] classes) : 
     execution(boolean Application.doSomething(int, Class<? extends String>...)) && 
     args(number, classes) 
    { 
     System.out.println(this.getClass().getName()); 
     System.out.println(thisJoinPointStaticPart); 
     System.out.print("number = " + number + ", classes = { "); 
     for (Class<? extends String> clazz : classes) 
      System.out.print(clazz.getName() + ", "); 
     System.out.println("}"); 
     return proceed(number, classes); 
    } 
} 

註解風格方面:

package de.scrum_master.aspect; 

import org.aspectj.lang.ProceedingJoinPoint; 
import org.aspectj.lang.annotation.Around; 
import org.aspectj.lang.annotation.Aspect; 

@Aspect 
public class AnnotationStyleAspect { 
    @Around(
     "execution(boolean de.scrum_master.app.Application.doSomething(int, Class<? extends String>...)) &&" + 
     "args(number, classes)" 
    ) 
    public Object myAdvice(ProceedingJoinPoint thisJoinPoint, int number, Class<? extends String>[] classes) throws Throwable { 
     System.out.println(this.getClass().getName()); 
     System.out.println(thisJoinPoint.getStaticPart()); 
     System.out.print("number = " + number + ", classes = { "); 
     for (Class<? extends String> clazz : classes) 
      System.out.print(clazz.getName() + ", "); 
     System.out.println("}"); 
     return thisJoinPoint.proceed(new Object[] { number, classes }); 
    } 
} 

輸出的示例積極兩個方面:

Starting application 
de.scrum_master.aspect.CodeStyleAspect 
execution(boolean de.scrum_master.app.Application.doSomething(int, Class[])) 
number = 11, classes = { java.lang.String, java.lang.String, } 
de.scrum_master.aspect.AnnotationStyleAspect 
execution(boolean de.scrum_master.app.Application.doSomething(int, Class[])) 
number = 11, classes = { java.lang.String, java.lang.String, } 
Doing something 
Stopping application 

正如你可以看到,這兩個方面基本相同的方式工作,併產生相同的結果。

+0

感謝您的關注,不幸的是,它不適用於我,即使簽名是正確的。我目前正在傾向於這是Spring-AOP的缺陷。鑑於你的發現,它看起來像另一個解決方法是使用本機AspectJ。 – chesterm8

+0

是的,原生AspectJ的使用在Spring中有很好的記錄,並且具有很多優點:沒有動態代理(即更高效),比方法攔截(即構造函數或setter/getter)更多的選項,適用於任何類春豆)。也許這也是一個版本的事情。我使用了AspectJ 1.8.0,儘管我認爲它也可以在1.7。*之類的舊版本中使用。 – kriegaex