簡體   English   中英

Spring AOP切入點不適用於varargs

[英]Spring AOP pointcut not working with varargs

當參數之一是vararg時,我無法使spring-AOP切入點工作。 給定以下代碼,我希望測試中的兩次調用都會觸發切入點,但是無論哪種情況都不會調用切入點。 我在同一個類的其他方法上有其他方面的工作,所以我知道這對我的測試或spring設置不是問題-它似乎與該方法隔離,唯一的區別是vararg。

方法聲明:

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);

編輯:

我可以確認,如果我從切入點和方法定義中刪除了定義的vararg部分(即,刪除了所有的“ ...”和“ []”),則它確實起作用,因此,這肯定與它們有關。 如果將“ ...”替換為“ []”,它也將不起作用。

我不是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

如您所見,這兩個方面基本上都以相同的方式工作,並產生相等的結果。

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

@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];
}

如果您需要為切入點指定參數以使其切入正確的位置,那么這顯然不夠好-幸運的是,事實並非如此。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM