【问题标题】:Spring AOP - Custom Annotation for Class and MethodSpring AOP - 类和方法的自定义注解
【发布时间】:2020-10-07 09:39:41
【问题描述】:

现有答案很好地解释了如何使用自定义注释进行方法执行时间记录。我想知道是否有办法对 Class 和 Method 使用相同的注解,但是 Pointcut 在使用的​​地方应该不同。

@LogExecutionTime
public class MyServiceImpl implements MyService {

    public void run(){
       // logic
    }

    public void walk(){
       // logic
    }

    private void breather(){
       // logic
    }
}

如果对类使用注释,则应考虑将类内的所有方法用于 Aspect 类中的执行时间日志记录(如 execution(* com.me.package.MyServiceImpl.*(..)))。但是,如果 Annotation 仅用于类内的单个方法,则还应考虑 Aspect Logging 类中的唯一方法。 (如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
    }
}

注解类

package com.myproj.core.utils.annotation;

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

import java.lang.annotation.Retention;

@Retention(RUNTIME)
public @interface LogExecutionTime {

}

注释的方面类(使用@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.xml中的Spring Bean定义

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

【问题讨论】:

  • 你放弃了吗?没有更多的反馈?它仍在我的后续列表中。
  • @kriegaex 抱歉,如前所述,它没有按预期工作。我试图只使用类级别,但不知何故它只记录公共方法。所以现在,我正在使用另一种方法,直接在@Around 中给出方法的限定名称。我肯定会实施这个,但现在它被搁置了。很抱歉给您带来麻烦。
  • 我确信我的回答是正确的。我能想到它对你不起作用的唯一原因是你的切入点错误。因为后者正是您在示例代码中隐藏的内容,所以问题暂时结束。我敢肯定,只要您使用具体的切入点更新代码,它就会重新打开。如果我有什么要分析的,我很乐意提供进一步的帮助。
  • 感谢@kriegaex,即使我确信这些切入点是正确的,但不知何故它们没有按预期工作。仅供参考,我已经添加了完整的方面类以及您提供的切入点。
  • 只是为了确保您没有忘记任何基本内容:如果您使用 Spring AOP,则切面和目标类都必须是 @Components 或声明为 @Beans(或更一般地说,必须由 Spring 管理)才能被 Spring AOP 拾取。我在您的代码中看不到任何此类内容。那么原始代码是什么样子的呢?

标签: java spring spring-boot spring-aop


【解决方案1】:

您的带有@annotation() 的示例代码没有意义,因为您没有指定方法注释类型。它应该类似于 @annotation(fully.qualified.AnnotationType)

对于匹配类注释,您想使用@within(fully.qualified.AnnotationType),如here 所述。

所以你可以使用类似的切入点

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

或者,根据我的回答here,你也可以使用更神秘的版本

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

【讨论】:

  • 谢谢,Pointcut 是我一直在寻找的缺失部分。我遵循了您的两种方法,但只有类级别注释触发方面,方法级别注释不知何故不起作用。
  • 然后你做了一些与我告诉你的不同的事情。您甚至没有提到您选择了两种方法中的哪一种。此外,“它不工作”并不是一个特别有用的问题描述。
  • 我尝试了@annotation(..execution 这两种方法,但似乎这些切入点仅适用于类级别注释,不适用于方法级别注释。我找到了另一个答案 stackoverflow.com/questions/36175368/… ,但它也给出了相同的结果。
  • 你认为用伪代码@Around("<pointcut to serve class annotation as well as method annotation>")更新你的问题是一个特别聪明的主意吗?正是您遇到问题的部分是您隐藏的内容。如果您真的需要帮助,请重新考虑您提出问题的方式,并准确且可重复地展示您的所作所为。这里的人都是开发人员,即他们想分析和解决问题,而不是猜测或推测。
  • @kriegaex :实际上这是我认为可行的,但对我也不起作用。我想在注释(使用@annotation(com.package.SomeCustomAnno) 很容易)以及其他可能的注释处有一个切入点,而这些注释又可以用@SomeCustomAnno(value = ..., bar = ...) 进行注释。可悲的是,我无法让“派生”注释起作用(这是问题:stackoverflow.com/q/68785567/15610035)。如果您知道如何对派生的注释做出反应,请告诉我,但此处提供的解决方案不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多