Вы делаете три базовых c неверных значения:
Вы пытаетесь сопоставить аннотации аргументов параметров из args()
, но там это не имеет никакого эффекта, поэтому processWithBody(..)
соответствует нежелательному параметру и связывает его с body
. Он должен быть переведен в execution()
pointcut.
Ваш синтаксис pointcut неверен, даже если вы перенесете его в execution()
, то есть что-то вроде
execution(* *(@org.springframework.web.bind.annotation.RequestBody *, ..))
будет соответствовать если тип (!) параметра имеет аннотацию @RequestBody
, а не сам параметр.
Для этого необходимо поместить сам параметр в скобки, например (*)
, то есть
execution(* *(@org.springframework.web.bind.annotation.RequestBody (*), ..))
.
Вы должны убедиться, что pointcut являются взаимоисключающими, в противном случае несколько советов должны совпадать на одной точке соединения. Чтобы быть точным, необходимо различать следующие случаи:
- методы, аннотированные
@Loggable
с первым параметром метода, аннотированным @RequestBody
- методы, аннотированные
@Loggable
с первым параметром метода не , аннотированным @RequestBody
- методами, аннотированными
@Loggable
без каких-либо параметров
Вот простой пример Java + AspectJ (без Spring или Spring AOP), но синтаксис аспекта должен быть идентичен в Spring AOP:
Аннотация + приложение драйвера:
package de.scrum_master.app;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(METHOD)
public @interface Loggable {}
package de.scrum_master.app;
import org.springframework.web.bind.annotation.RequestBody;
public class Application {
public static void main(String[] args) {
Application application = new Application();
application.doNotLogMe("foo", 11);
application.doNotLogMeEither();
application.doNotLogMeEither("foo", 11);
application.logMe("foo", 11);
application.logMeToo("foo", 11);
application.logMeToo();
}
public void doNotLogMe(@RequestBody String body, int number) {}
public void doNotLogMeEither() {}
public void doNotLogMeEither(String body, int number) {}
@Loggable public void logMe(@RequestBody String body, int number) {}
@Loggable public void logMeToo(String body, int number) {}
@Loggable public void logMeToo() {}
}
Аспект:
Как вы можете видеть, я использую дифференцирование трех упомянутых выше случаев, а также удовлетворяю вашу потребность в общем вспомогательном методе, который я назвал logIt(..)
. Там вы можете поместить все сложные средства ведения журналов, которые хотите использовать, без дублирования кода в ваших методах рекомендаций.
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class MyAspect {
@Pointcut("@annotation(de.scrum_master.app.Loggable)")
public void loggableAnnotation() {}
@Around(
"loggableAnnotation() && " +
"execution(* *())"
)
public Object simpleProcessWithoutParameters(ProceedingJoinPoint joinPoint) throws Throwable {
return logIt(joinPoint, null);
}
@Around(
"loggableAnnotation() && " +
"execution(* *(!@org.springframework.web.bind.annotation.RequestBody (*), ..))"
)
public Object simpleProcessWithParameters(ProceedingJoinPoint joinPoint) throws Throwable {
return logIt(joinPoint, null);
}
@Around(
"loggableAnnotation() && " +
"execution(* *(@org.springframework.web.bind.annotation.RequestBody (*), ..)) && " +
"args(body, ..)"
)
public Object processWithBody(ProceedingJoinPoint joinPoint, Object body) throws Throwable {
return logIt(joinPoint, body);
}
private Object logIt(ProceedingJoinPoint joinPoint, Object body) throws Throwable {
System.out.println(joinPoint + " -> " + body);
return joinPoint.proceed();
}
}
Журнал консоли:
execution(void de.scrum_master.app.Application.logMe(String, int)) -> foo
execution(void de.scrum_master.app.Application.logMeToo(String, int)) -> null
execution(void de.scrum_master.app.Application.logMeToo()) -> null
PS: разница между execution(* *(@MyAnn *))
и execution(* *(@MyAnn (*)))
тонкая и поэтому хитрая. К сожалению, это не задокументировано должным образом здесь , где это должно быть. Если быть точным, последний случай вообще не документирован, возможно, только в некоторых заметках о выпуске AspectJ и, конечно, в модульных тестах. Но ни один нормальный пользователь не заглянет туда.