首页 > 解决方案 > 如何扫描/检查包中的 Java 类以获取 @slf4j 注释

问题描述

groovy 和 Spring 的新手,试图帮助我们的开发团队在我们的框架中使用一些日志记录功能。

我创建了一个 MethodLogging Aspect 来记录任何带有 @Loggable 注释的类的方法执行时间。

但是,作为第二阶段,我需要确定给定包中的类是否使用 @slf4j 注释并执行 slf4j 日志记录功能而不是 @Loggable。

这是方面代码

import groovy.util.logging.Slf4j
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.Configuration

@Aspect
@Slf4j
public class LoggingAspect {
  // This is a Logging Aspect for the Loggable annotation that calculates
  // method runtimes for all methods under classes annotated with @Loggable

  @Around('execution (* *(..)) && @within(com.zions.common.services.logging.Loggable)')
  public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
    long start = System.currentTimeMillis();
    Object proceed = joinPoint.proceed();
    long executionTime = System.currentTimeMillis() - start;
    log.info("${joinPoint.getSignature()} executed in ${executionTime}ms");
    return proceed;
  }
}

这是@Loggable 注释代码

package com.zions.common.services.logging

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

// Logging annotation to be used at class level

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Loggable {}

任何关于如何进行这项工作的想法或资源将不胜感激。

标签: slf4jspring-aop

解决方案


原则上,如果(且仅当)在运行时字节码中仍然存在,拦截@Slf4j将与您自己的自定义注释相同。但事实上并非如此。正如您在注释源代码中看到的那样,它具有保留性。 @Slf4jSOURCE

背景:@Slf4jGroovy 编译器使用注解来在编译期间动态创建静态记录器,从而将您保存为 Groovy 类中的用户样板代码。如果你反编译这个类......

package de.scrum_master.stackoverflow

import groovy.util.logging.Slf4j

@Slf4j
class FooBarZot {
  void test() {
    log.info("test")
  }
}

...你会看到这样的东西:

package de.scrum_master.stackoverflow;

import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
import org.codehaus.groovy.runtime.callsite.CallSite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FooBarZot implements GroovyObject {
  private static final transient Logger log;

  public FooBarZot() {
    CallSite[] var1 = $getCallSiteArray();
    super();
    MetaClass var2 = this.$getStaticMetaClass();
    this.metaClass = var2;
  }

  public void test() {
    CallSite[] var1 = $getCallSiteArray();
    var1[0].call(log, "test");
  }

  static {
    Object var0 = $getCallSiteArray()[1].call(LoggerFactory.class, "de.scrum_master.stackoverflow.FooBarZot");
    log = (Logger)ScriptBytecodeAdapter.castToType(var0, Logger.class);
  }
}

因此,AspectJ 不会@Slf4j仅仅因为它在运行时不存在而帮助您拦截注释。你需要找到另一种方法来实现你想要的。一种这样的方法可能是注释处理,因为它是在编译之前完成的。


推荐阅读