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" в качестве значения.

Заметка

  1. Я пытаюсь избежать написания другого метода, как findUserComments().

  2. Я хочу поддерживать согласованность во всем приложении. Существуют и другие классы с похожими шаблонами операций 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()вы все еще можете выделить эти вещи в вспомогательные методы и вызывать их из обоих советов.

Другие вопросы по тегам