简体   繁体   中英

Custom annotation not being called

I'm trying to time methods via annotations, I've found plenty of information about how to time executions of things, and I feel like I'm close but my console isn't getting any output.

The jist of what I'm trying to do

    public static void main(String[] args) {
        Simpleton simp = new Simpleton();
        simp.howLongDidThisTake();
    }

    @MethodTimer
    public void howLongDidThisTake() {
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

My Interface

package com.lixar.apba.aop.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodTimer{
}

and my advice/service class for the functionality attached to it.

package com.lixar.apba.aop.annotations;

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

import java.util.HashMap;
import java.util.Map;

@Aspect
@Component
public class MethodTimerService {
    Logger logger = LoggerFactory.getLogger(MethodTimerService.class);
    static Map<String, Long> loggedMethods = new HashMap<>();
    String signature = null;

    @Around("@annotation(com.lixar.apba.aop.annotations.MethodTimer)")
    public Object methodTimer(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object callback = proceedingJoinPoint.proceed();
        long endTime = System.currentTimeMillis();
        insertLoggedExecution(proceedingJoinPoint, startTime, endTime);
        return callback;
    }

    private void insertLoggedExecution(ProceedingJoinPoint pjp, long startTime, long endTime) {
        signature = String.valueOf(pjp.getSignature());
        long calculatedTime = getCalculatedTime(startTime, endTime);
        loggedMethods.put(String.valueOf(pjp.getSignature()), calculatedTime);
        System.out.println("Method name: " + signature + " : TotalExecutionTime: " + calculatedTime);
    }

    private long getCalculatedTime(long startTime, long endTime) {
        long calculatedTime = endTime - startTime;
        if(loggedMethods.containsKey(signature)) {
            calculatedTime = endTime - startTime + loggedMethods.get(signature);
        }
        return calculatedTime;
    }

    public static void outPutLoggedExecution() {
        for(var log : loggedMethods.entrySet()) {
            System.out.println("Method name: " + log.getKey() + " : TotalExecutionTime: " + log.getValue());
        }
    }
}

The annotation is never being called, how can I fix this?

Configuration
First of all, you need to configure your IDE to work with AspectJ.
1. Configuration for IntelliJ

2. Configuration for Eclipse

3. Spring configuration documentation

4. Spring Boot configuration

Code changes

  1. Using @Pointcut

Declare @Pointcut for your custom @MethodTimer annotation

    @Pointcut("@annotation(methodTimer)")
    public void callMethod(MethodTimer methodTimer) { }

Pointcut: A predicate that matches join points. Advice is associated with a pointcut expression and runs at any join point matched by the pointcut (for example, the execution of a method with a certain name). The concept of join points as matched by pointcut expressions is central to AOP: Spring uses the AspectJ pointcut language by default.

Bind Pointcut with your @Around advice. Also, you need to restrict @Around advice only for execution, otherwise method will be called twice: Why does AspectJ @Around advice execute twice?

    @Around("callMethod(methodTimer) && execution(* *(..))")
    public Object methodTimer(ProceedingJoinPoint proceedingJoinPoint, MethodTimer methodTimer) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object callback = proceedingJoinPoint.proceed();
        long endTime = System.currentTimeMillis();
        insertLoggedExecution(proceedingJoinPoint, startTime, endTime);
        return callback;
    }
  1. Another variant, custom annotation binding
    @Around("@annotation(methodTimer) && execution(* *(..)) ")
    public Object methodTimer(ProceedingJoinPoint proceedingJoinPoint, MethodTimer methodTimer) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object callback = proceedingJoinPoint.proceed();
        long endTime = System.currentTimeMillis();
        insertLoggedExecution(proceedingJoinPoint, startTime, endTime);
        return callback;
    }

Full code:

public static void main(String[] args) {
    Simpleton simp = new Simpleton();
    simp.howLongDidThisTake();
}

public class Simpleton {
    @MethodTimer
    public void howLongDidThisTake() {
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodTimer{
}

@Aspect
@Component
public class MethodTimerService {
    static Map<String, Long> loggedMethods = new HashMap<>();
    String signature = null;

    @Pointcut("@annotation(methodTimer)")
    public void callMethod(MethodTimer methodTimer) { }

    @Around("callMethod(methodTimer) && execution(* *(..)) ")
    public Object methodTimer(ProceedingJoinPoint proceedingJoinPoint, MethodTimer methodTimer) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object callback = proceedingJoinPoint.proceed();
        long endTime = System.currentTimeMillis();
        insertLoggedExecution(proceedingJoinPoint, startTime, endTime);
        return callback;
    }

    private void insertLoggedExecution(ProceedingJoinPoint pjp, long startTime, long endTime) {
        signature = String.valueOf(pjp.getSignature());
        long calculatedTime = getCalculatedTime(startTime, endTime);
        loggedMethods.put(String.valueOf(pjp.getSignature()), calculatedTime);
        System.out.println("Method name: " + signature + " : TotalExecutionTime: " + calculatedTime);
    }

    private long getCalculatedTime(long startTime, long endTime) {
        long calculatedTime = endTime - startTime;
        if(loggedMethods.containsKey(signature)) {
            calculatedTime = endTime - startTime + loggedMethods.get(signature);
        }
        return calculatedTime;
    }

    public static void outPutLoggedExecution() {
        for(Map.Entry<String, Long> log : loggedMethods.entrySet()) {
            System.out.println("Method name: " + log.getKey() + " : TotalExecutionTime: " + log.getValue());
        }
    }
}

Program execution result

Method name: void Simpleton.howLongDidThisTake() : TotalExecutionTime: 55

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