自定义注释作为方法日志记录的拦截器

2022-09-01 03:39:55

Java Gurus,

我是新手,没有搜索过很多,所以请忍受我...annotations

我想实现一个将调用的方法;从非常基本的东西开始,它可以只打印方法名称和参数,这样我就可以避免语句。Custom Annotationinterceptlogger

示例调用如下所示:

public MyAppObject findMyAppObjectById(Long id) throws MyCustomException {
    log.debug("in findMyAppObjectById(" + id + ")");
    //....
}   

可以转换为:

@LogMethodCall(Logger.DEBUG)
public MyAppObject findMyAppObjectById(Long id) throws MyCustomException {
    //....
}   

我能得到一些关于这一点的提示吗?


答案 1

根据您对我的评论的回答,您将无法仅通过注释来执行此操作。当然,您可以创建注释并创建一些反射代码,然后检测到并执行一些代码,但这不会对代码进行太大更改,因为在调用方法之前需要调用该方法,我认为这不会对您有太大帮助,因为您需要在每次调用之前调用解析器方法。parser

如果你需要你提到的行为(自动调用),你需要将你的注释与一些AOP框架(如Spring(普通Java)或AspectJ(AspectJ代码))相结合。然后,您可以设置切入点,每次达到此点时,可能会执行一些代码。然后,您可以配置为在方法执行之前和/或之后执行一些代码。

如果第一种方案足够,则可以执行如下操作:

记录器:枚举

public enum Logger {
    INFO,
    DEBUG;
}

LogMethodCall: annotation

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

@Retention( RetentionPolicy.RUNTIME ) // the annotation will be available during runtime
@Target( ElementType.METHOD )         // this can just used in methods
public @interface LogMethodCall {

    Logger logLevel() default Logger.INFO;

}

人员:带注释的类

public class Person {

    // will use the default log level (INFO)
    @LogMethodCall
    public void foo( int a ) {
        System.out.println( "foo! " + a );
    }

    @LogMethodCall( logLevel = Logger.DEBUG )
    public void bar( int b ) {
        System.out.println( "bar! " + b );
    }

}

Utils: 具有日志静态方法的类(这将执行“解析”)

public class Utils {

    public static void log( Object o, String methodName ) {

        // gets the object class
        Class klass = o.getClass();

        // iterate over its methods
        for ( Method m : klass.getMethods() ) {

            // verify if the method is the wanted one
            if ( m.getName().equals( methodName ) ) {

                // yes, it is
                // so, iterate over its annotations
                for ( Annotation a : m.getAnnotations() ) {

                    // verify if it is a LogMethodCall annotation
                    if ( a instanceof LogMethodCall ) {

                        // yes, it is
                        // so, cast it
                        LogMethodCall lmc = ( LogMethodCall ) a;

                        // verify the log level
                        switch ( lmc.logLevel() ) {
                            case INFO:
                                System.out.println( "performing info log for \"" + m.getName() + "\" method" );
                                break;
                            case DEBUG:
                                System.out.println( "performing debug log for \"" + m.getName() + "\" method" );
                                break;
                        }

                    }
                }

                // method encountered, so the loop can be break
                break;

            }

        }

    }

}

注释处理:带有代码的类,用于测试注释处理

public class AnnotationProcessing {

    public static void main(String[] args) {

        Person p = new Person();
        Utils.log( p, "foo" );
        p.foo( 2 );
        Utils.log( p, "bar" );
        p.bar( 3 );

    }
}

当然,您需要改进我的代码以满足您的需求。这只是一个起点。

有关注释的更多信息:

有关 AOP 的更多信息:


答案 2

使用Spring AOP和Java Annotation。Spring AOP否定了编写一个util类来使用Java Reflection解析Java类的要求。

示例 -

  1. 自定义注释 -

     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.METHOD)
     public @interface A {            
          boolean startA() default false;
    
          boolean endA() default false;
     }
    
  2. 方面-

      @Aspect
      public class AAspect {
          @Pointcut(value = "execution(* *.*(..))")
          public void allMethods() {
                  LOGGER.debug("Inside all methods");
          }
    
         @Before("allMethods() && @annotation(A)")
         public void startAProcess(JoinPoint pjp, A a) throws Throwable {
              if (a.startA()) {
                    //Do something
         }
     }
    
  3. 启用 AspectJ -

     @Configuration
     @EnableAspectJAutoProxy
     public class AConfig {
    
     }
    
  4. 在代码中使用 -

     @A(startA = true, endA = true)
     public void setUp(){
           //Do something- logic
     }
    

推荐