当其中一个参数是vararg时,我无法使spring-AOP切入点工作。鉴于下面的代码,我原本期望在我的测试的两个调用中触发切入点,但是在任何一种情况下都不会调用它。我有其他方面在同一个类中处理其他方法,所以我知道它不是我的测试或弹簧设置的问题 - 它似乎与此方法隔离,唯一独特的是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部分(即删除所有'...'和'[]'),那么它确实与某些事情有关那些。如果我用'[]'替换'...',它也不起作用。
答案 0 :(得分: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
正如您所看到的,这两个方面基本上以相同的方式工作并产生相同的结果。
答案 1 :(得分: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];
}
如果您需要指定切入点的参数以便在正确的位置切割,这显然不够好 - 幸运的是,对于我来说并非如此。