Spring AoP, выражение pointcut для перегруженных методов с одинаковыми типами параметров
Я определил класс для операций CRUD над комментариями. Метод чтения перегружен.
class Comment{
// method 1: returns all the comments by a user
findAll(long userId, long subjectId, String param);
// method 2: returns all the comments of all the users
findAll(long subjectId, String param)
}
Выражение точки среза, которое я пробовал
@Around("execution(* com.package..*Controller.findAll(..)) && args(userId,subjectId,..)")
public Object validateFindAll(final ProceedingJoinPoint proceedingJoinPoint, final long userId, final long subjectId) {
// validate userId, if available
// validate subjectId
}
Проблема: Поскольку типы данных для userId и subjectId одинаковы, выражение точки при применении к методу 2 смещает значения параметра на 1 место. Это означает, что выражение не понимает, что первый параметр userId не передан. Вместо этого userId получает "subjectId" в качестве значения, а subjectId получает соседний параметр "param" в качестве значения.
Заметка
Я пытаюсь избежать написания другого метода, как findUserComments().
Я хочу поддерживать согласованность во всем приложении. Существуют и другие классы с похожими шаблонами операций CRUD.
Вопрос: возможно ли определить выражение, применимое к обоим методам, при этом первый параметр userId является необязательным?
РЕДАКТИРОВАТЬ - Решение В то время как я играл с различными подходами, как предложено в решениях ниже, я наконец удалил метод 2. Я обрабатываю этот случай в методе 1.
2 ответа
Проблема связана с методом загрузки на самом деле. Поскольку вы передаете long userId и long subjectId AOP всегда будет пытаться соответствовать этим аргументам. Решения могут быть
1) Создайте еще один pointcut для другого аргумента, т.е. 1 для long, long и other для long, String
2) Используйте переменную подпись аргумента в начале, такую как
@Around("execution(* com.org..findAll(..)) && args(..,subjectId,param)")
public Object validateFindAll(final ProceedingJoinPoint joinPoint, final long userId, final long subjectId) {
}
вместо использования аргумента переменной в начале. Затем вы можете использовать метод getArgs(), чтобы выяснить аргументы. Это простое решение, но может замедлить вашу обработку.
3) Хотя, как проблема дизайна, я бы предложил заключить все ваши параметры в один объект и передать его. Вместо передачи нескольких параметров. Это поможет вам и в будущем.
Вы не можете явно связать параметр AspectJ и затем ожидать, что он будет соответствовать несовместимой подписи. Таким образом, ваш pointcut будет соответствовать только findAll(long, long, ..)
т. е. "метод 1" в вашем примере. Вы можете указать дополнительные аргументы с ..
, но тогда вы не можете связать их с именованными параметрами.
Например, можно сопоставить оба метода и связать long subjectId
а также String param
с помощью args(.., subjectId, param)
потому что оба параметра предсказуемо выровнены по правому краю в конце подписи. Если вам нужен какой-либо необязательный (и, следовательно, несвязанный) параметр, вам необходимо использовать thisJoinPoint.getArgs()
:
@Around("execution(* com.package..*Controller.findAll(..)) && args(.., subjectId, param)")
public Object validateFindAll(
final ProceedingJoinPoint thisJoinPoint,
final long subjectId,
final String param
) {
if (thisJoinPoint.getArgs().length == 3)
System.out.println(thisJoinPoint + " -> " + thisJoinPoint.getArgs()[0] + ", " + subjectId + ", " + param);
else
System.out.println(thisJoinPoint + " -> " + subjectId + ", " + param);
// (...)
}
Но пока getArgs()
динамический, он, вероятно, медленнее, чем привязка параметров, потому что он использует отражение. Может быть, иметь два pointcut не так уж и плохо. Если ваш метод совета делает сложные вещи до / после proceed()
вы все еще можете выделить эти вещи в вспомогательные методы и вызывать их из обоих советов.