Мы применяем "до" рекомендации с использованием пользовательских аннотаций, чтобы выполнять только определенные методы, если применяется бизнес-логика (неинтересная для этой проблемы).
Мы видим, что этот аспект называется дважды для каждого вызова метода.
Отладка в нем я вижу, Cglib2AopProxy$CglibMethodInvocation.proceed
имеет массив, называемый: interceptorsAndDynamicMethodMatchers
. Этот массив перечисляет наш PointCut ("RequiresX")
дважды.
Вот точка соединения:
@Before(@annotation(requiresX)")
public Object process(ProceedingJoinPoint joinPoint, RequiresACL requiresX) throws Throwable
{
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
log.info(" method:" + method.getName());
// do business logic of the aspect…
log.info(" joinPoint.proceed with call to " + method.getName());
}
и вот наша пользовательская аннотация
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.Method)
public @interface RequiresX {
}
и вот метод, который мы можем перехватить:
@RequiresX()
public String someMethod() {
....
}
Это кажется довольно ванильным, но я ясно сделал что-то не так. Любые предложения о том, как выполнять только один раз за звонок, будут очень признательны.
Мы нашли ответ как путем проб и ошибок, так и через эту должность: http://forum.spring.io/forum/spring-projects/aop/25729-advice-is-called-twice-with-aop-auto-proxy- конфигурация
Итог: мы имели аннотацию @Aspect в классе аспект, а также указывали аспект в файле Spring. Не делай того и другого.
вы должны напечатать Pointcut и увидеть проблему как:
@Before(@annotation(requiresX)")
public Object process(ProceedingJoinPoint joinPoint, RequiresACL requiresX) throws Throwable
{
log.info(" pointcut:" + joinPoint.getKind());
// do business logic of the aspect…
}
он напечатает проблему как:
pointcut:method-call
pointcut:method-execution
Итак, вы должны изменить Pointcut как:
@Before(@annotation(RequiresX) && execution(@RequiresX * *.*(..)))