简体   繁体   中英

Spring AOP - Custom Annotation for Class and Method

Existing answers gives nice explanation on how to use Custom Annotation for method execution time logging. I am wondering if there is way to use same annotation for both Class and Method, but Pointcut should be different where it is used.

@LogExecutionTime
public class MyServiceImpl implements MyService {

    public void run(){
       // logic
    }

    public void walk(){
       // logic
    }

    private void breather(){
       // logic
    }
}

If Annotation is used for class all methods inside class should be considered for Execution Time Logging in Aspect Class (like execution(* com.me.package.MyServiceImpl.*(..)) ). However if the Annotation is only used for single method inside the class, it is should also consider that only method in Aspect Logging Class. (like execution(* com.you.package.YourServiceImpl.forward(..)) ).

public class YourServiceImpl implements YourService {

    @LogExecutionTime
    public void forward(){
       // logic
    }

    @LogExecutionTime
    public void backward(){
       // logic
    }

    private void upward(){
       // logic
    }
}

Annotation Class

package com.myproj.core.utils.annotation;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;

@Retention(RUNTIME)
public @interface LogExecutionTime {

}

Aspect Class for Annotation (using pointcuts as suggested by @kriegaex)

package com.myproj.core.utils;

import java.time.Duration;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import java.time.Instant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Aspect class to Log Method Execution time
 */
@Aspect
public class MyMethodExecutionLoggingAspect {
    
    private static final Logger LOG = LoggerFactory.getLogger(MyMethodExecutionLoggingAspect.class);
    
    /**
     * This method will log Method Execution Time
     * 
     * @param joinPoint
     * @return object
     * @throws Throwable
     */
    @Around("execution(* (@com.myproj.core.utils.annotation.LogExecutionTime *).*(..)) || execution(@com.myproj.core.utils.annotation.LogExecutionTime * *(..))")
    public Object log(ProceedingJoinPoint joinPoint) throws Throwable {

        String className = joinPoint.getTarget().getClass().getSimpleName();
        String methodName = joinPoint.getSignature().getName();
        Instant start = Instant.now();

        try {
            return joinPoint.proceed();
        } finally {

            long end = Duration.between(start, Instant.now()).toMillis();

            if (end > 0) {
                LOG.debug("METHOD EXECUTION TIME LAPSED: {}ms | {}.{}", end, className, methodName);
            }
        }

    }
    
}

Spring Bean Definition in spring.xml

<bean class="com.myproj.core.utils.MyMethodExecutionLoggingAspect" />

Your sample code with @annotation() does not make sense because you do not specify a method annotation type. It should be something like @annotation(fully.qualified.AnnotationType) instead.

For matching class annotations you want to use @within(fully.qualified.AnnotationType) , as described here .

So you could use a pointcut like

@annotation(fully.qualified.AnnotationType)
  || @within(fully.qualified.AnnotationType)

Alternatively, according to my answer here , you could also use the more cryptic version

execution(* (@fully.qualified.AnnotationType *).*(..))
  || execution(@fully.qualified.AnnotationType * *(..))

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