Весна АОП. Как сделать pointcut для всех публичных методов в аннотированном классе

Мне нужно обработать все исключения, которые возникают из общедоступных методов класса, аннотированных некоторыми аннотациями. Я пытаюсь использовать Spring AOP. Это мой регистратор:

@Aspect
public class Logger {
    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Pointcut("@annotation(loggable)")
    public void isLoggable(Loggable loggable) {
    }

    @AfterThrowing(pointcut = "isLoggable(loggable)", throwing = "e")
    public void afterThrowing(Loggable loggable, Exception e) throws Throwable {
        log.error("AFTER", e);
    }

@Loggable - моя аннотация.

Затем я добавил аннотацию @EnableAspectJAutoProxy в свой класс конфигурации.

Сначала я попытался аннотировать некоторый метод, который вызывает исключение. Он работает нормально, но как я могу заставить это работать для всех общедоступных методов в классе, аннотированных аннотацией @Loggable?


person Kirill    schedule 24.03.2017    source источник
comment
Является ли ваш Logger _2 _... @Aspect не @Component, и поэтому компоненты не будут сканироваться. Итак, либо зарегистрируйте его как bean-компонент, либо добавьте @Component для его обнаружения, либо создайте @ComponentScan для сканирования всех bean-компонентов, помеченных @Aspect. В любом случае ваш аспект должен стать bean-компонентом, иначе он не существует, и ничего не произойдет.   -  person M. Deinum    schedule 24.03.2017
comment
Ваше решение с советом @around является правильным. Попробуйте отладить, проверяйте каждый раз, когда выполняется совет.   -  person Marcin Tarka    schedule 24.03.2017
comment
@ M.Deinum Спасибо! Это была очень глупая ошибка.   -  person Kirill    schedule 24.03.2017
comment
@ M.Deinum Это работает, если метод аннотирован @Loggable, но мне нужен аспект для работы со всеми общедоступными методами в аннотированном классе   -  person Kirill    schedule 24.03.2017
comment
@ M.Deinum, я знаю, что ты всегда самоотвержен, не жаден до очков репутации и часто даешь правильный ответ в виде простого комментария. Но при этом соответствующие вопросы остаются без ответа. Не могли бы вы написать короткие ответы в таких случаях, чтобы ОП мог их принять? Было бы здорово, заранее спасибо. :-)   -  person kriegaex    schedule 24.03.2017
comment
Обновление: Видите, что только что произошло, @ M.Deinum? Кто-то еще отправил ответ, хотя проблема OP уже решена.   -  person kriegaex    schedule 24.03.2017


Ответы (2)


Вы можете создать такой аспект, где @LogMe - это аннотация: @Pointcut("execution(@LogMe * *(..))") для соответствия всем общедоступным методам.

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;


@Aspect
@Component
public class LogExecutionTime {

    private static final String LOG_MESSAGE_FORMAT = "%s.%s execution time: %dms";
    private static final Logger logger = LoggerFactory.getLogger(LogExecutionTime.class);

    @Pointcut("execution(@LogMe * *(..))")
    public void isAnnotated() {}

    /**
     * Method will add log statement of running time of the methods which are annotated with @LogMe
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("isAnnotated()")
    public Object logTimeMethod(ProceedingJoinPoint joinPoint) throws Throwable {
      StopWatch stopWatch = new StopWatch();
      stopWatch.start();

      Object retVal = joinPoint.proceed();

      stopWatch.stop();

      logExecutionTime(joinPoint, stopWatch);

      return retVal;
    }

    private void logExecutionTime(ProceedingJoinPoint joinPoint, StopWatch stopWatch) {
      String logMessage = String.format(LOG_MESSAGE_FORMAT, joinPoint.getTarget().getClass().getName(), joinPoint.getSignature().getName(), stopWatch.getTotalTimeMillis());
      logger.info(logMessage.toString());
    }
}
person Mahesh Kumar    schedule 24.03.2017

Класс, помеченный @Aspect, не является @Component, поэтому, если у вас включено сканирование компонентов, он не будет обнаружен. Если в вашем контексте нет аспекта, АОП бесполезен.

Чтобы исправить это, вы можете сделать 1 из 3 вещей:

  1. Поместите @Component рядом с @Aspect
  2. Определите @Aspect как @Bean
  3. Добавьте дополнительный `@ComponentScan (includeFilter = {@ Filter (org.aspectj.lang.annotation.Aspect)}

Очевидно, вариант №1 сделать проще всего.

Сначала я попытался аннотировать некоторый метод метода, который вызывает исключение. Он работает нормально, но как я могу заставить это работать для всех общедоступных методов в классе, аннотированных аннотацией @Loggable?

Вам нужно написать точечный разрез, который соответствует этому. Что-то вроде следующего должно помочь.

@Pointcut("public * ((@Loggable *)+).*(..)) && within(@Loggable *)")

вместе с

@Pointcut("@Loggable * *(..)")

Что ударит по аннотированным методам или общедоступным методам в аннотированных классах. Это вдохновлено кодом из _ 9_ из Spring Framework.

person M. Deinum    schedule 24.03.2017