简体   繁体   中英

Spring AOP. How to make pointcut for all public methods in annotated class

I need to handle all the exceptions that are thrown from public methods of class annotated with some annotation. I trying to use Spring AOP. This is my logger:

@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 is my annotation.

Then I've added @EnableAspectJAutoProxy annotation to my configuration class.

First I've tried to annotate some method that throws an exception. It works fine but how can I make this work for all public methods in class annotated with @Loggable annotation?

You can create the aspect like this, where @LogMe is the annotation: @Pointcut("execution(@LogMe * *(..))") to match all the public methods.

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());
    }
}

A class annotated with @Aspect isn't a @Component so if you have component scanning enabled it won't be picked up. If there is no Aspect in your context, there is nothing use for AOP.

To fix this you can do 1 of 3 things:

  1. Put @Component next to the @Aspect
  2. Define the @Aspect as a @Bean
  3. Add an additional `@ComponentScan(includeFilter={@Filter(org.aspectj.lang.annotation.Aspect)}

Obviously option #1 is the easiest to do.

First I've tried to annotate some method method that throws an exception. It works fine but how can I make this work for all public methods in class annotated with @Loggable annotation?

You need to write a point cut that matches that. Something like the following should do the trick.

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

together with

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

Which will hit for annotated methods or public methods in annotated classes. This is inspired by the code from the AnnotationTransactionAspect from the Spring Framework.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM