Изменить подпись метода с @Aspect - PullRequest
0 голосов
/ 21 марта 2019

Можете ли вы изменить подпись метода в Spring, используя аспекты?

Как эффективно преобразовать следующее:

@GetMapping("/thing")
@User // custom annotation that should authenticate the user
public ResponseEntity getThing() {
    ... // user is successfully authenticated, get the "thing" from the database
}

в:

@GetMapping("/thing")
public ResponseEntity getThing(@CookieValue("Session-Token") String sessionToken) {
    User user = authenticator.authenticateSessionTokenOrThrow(sessionToken);
    ... // user is successfully authenticated, get the "thing" from the database
}

С помощью user переменная также становится доступной для использования в теле метода.

Если нет, как я могу достичь того же результата, не повторяя код (вызов параметра и средства проверки подлинности) везде?

1 Ответ

1 голос
/ 22 марта 2019

Аспекты не предназначены для этого.

Да, они могут эффективно изменять .class байт-код файлов, с компиляцией времени компиляции или времени выполнения, но они не переопределяют сигнатуры методов.

Кроме того, аспекты Spring AOP по умолчанию реализованы на чистом Java и поэтому не могут касаться уровня байт-кода. Для этого вам понадобится AspectJ.

Инструменты для настройки байт-кода во время выполнения / компиляции: ASM , ByteBuddy , CGLIB или Javassist.


Однако , вы, вероятно, можете сделать это с помощью Процессора аннотаций , который позволяет вам изменять фактические источники вместо уже скомпилированного байт-кода.


Если нет, как я могу достичь того же результата, не повторяя код (вызов параметра и аутентификатора) везде?

Возможные решения

  1. HandlerInterceptor , который просто выбрасывает Exception, если пользователь не аутентифицирован
  2. Стандартный совет Spring AOP, который просто выдает Exception, если пользователь не аутентифицирован
  3. Spring Security

1 довольно просто.
2 занимает больше времени
3 imho, кажется, лучше всего подходит для аутентификации, но оно самое сложное, вероятно


HandlerInterceptor может выбирать, к каким методам он применяется?

Нет, к сожалению. У меня было требование пару месяцев назад «покрыть» только определенные методы Interceptor, и я реализовал собственное решение, которое просто ищет аннотацию, указанную в самом методе.

Это фрагмент моего пользовательского HandlerInterceptor, который ищет аннотацию CheckInit, сначала для типа, а затем для метода, для более конкретной настройки.

@Override
public boolean preHandle(
        final HttpServletRequest request,
        final HttpServletResponse response,
        final Object handler
) throws Exception {
    if (handler instanceof HandlerMethod) {
        if (shouldCheckInit((HandlerMethod) handler)) {
            checkInit();
        }
    }

    return true;
}

private static boolean shouldCheckInit(final HandlerMethod handlerMethod) {
    final var typeAnnotation = handlerMethod.getBeanType().getAnnotation(CheckInit.class);
    final var shouldCheckInit = typeAnnotation != null && typeAnnotation.value();

    final var methodAnnotation = handlerMethod.getMethodAnnotation(CheckInit.class);
    return (methodAnnotation == null || methodAnnotation.value()) && shouldCheckInit;
}

private void checkInit() throws Exception {
    if (!manager.isActive()) {
        throw new NotInitializedException();
    }
}

"Стандартный Spring AOP advice" кажется интересным, у вас есть ссылка за что?

Документация Spring AOP - ищите конфигурацию на основе Java (я ненавижу XML)

AspectJ действительно касается байт-кода и может также изменять сигнатуры?

Вы можете заставить AspectJ изменять сигнатуры. Просто разветвите проект и измените его Java-агент или компилятор.

Процессоры аннотаций AFAIK не могут изменять классы, они могут только создавать новые.

Дело в том, что они не изменяют файлы .class, вместо этого они изменяют исходные файлы, что означает, что они просто редактируют их. Например. Lombok использует обработку аннотаций для изменения исходных файлов.

Но да, измененные источники записываются в новый файл.

...