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

SiB*_*SiB 24 java logging annotations interceptor

Java大师,

我很新,annotations并没有搜索过这个,所以请耐心等待...

我想实现Custom Annotation这将intercept一个方法调用.从非常基本的东西开始,它可以只打印方法名称和参数,以便我可以避免使用该logger语句.

像这样的示例调用:

public MyAppObject findMyAppObjectById(Long id) throws MyCustomException {
    log.debug("in findMyAppObjectById(" + id + ")");
    //....
}   
Run Code Online (Sandbox Code Playgroud)

可以转换成:

@LogMethodCall(Logger.DEBUG)
public MyAppObject findMyAppObjectById(Long id) throws MyCustomException {
    //....
}   
Run Code Online (Sandbox Code Playgroud)

我可以得到一些关于此的提示吗?

dav*_*tto 37

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

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

如果第一个场景足够,您可以执行以下操作:

记录器:枚举

public enum Logger {
    INFO,
    DEBUG;
}
Run Code Online (Sandbox Code Playgroud)

LogMethodCall:注释

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;

}
Run Code Online (Sandbox Code Playgroud)

人:注释类

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 );
    }

}
Run Code Online (Sandbox Code Playgroud)

Utils:带有log static方法的类(这将执行"解析")

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;

            }

        }

    }

}
Run Code Online (Sandbox Code Playgroud)

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

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 );

    }
}
Run Code Online (Sandbox Code Playgroud)

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

有关注释的更多信息:

关于AOP的更多信息:


Ari*_*aha 20

使用Spring AOP和Java Annotation.Spring AOP否定了使用Java Reflection编写用于解析Java类的util类的要求.

示例 -

  1. 自定义注释 -

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface A {            
         boolean startA() default false;
    
         boolean endA() default false;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  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
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 启用AspectJ -

    @Configuration
    @EnableAspectJAutoProxy
    public class AConfig {
    
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 在代码中使用 -

    @A(startA = true, endA = true)
    public void setUp(){
          //Do something- logic
    }
    
    Run Code Online (Sandbox Code Playgroud)


yeg*_*256 5

正如已经建议的,AOP 和注释是最好的选择。我建议使用jcabi-aspects的现成机制(我是开发人员):

@Loggable(Loggable.DEBUG)
public String load(URL url) {
  return url.openConnection().getContent();
}
Run Code Online (Sandbox Code Playgroud)

所有方法调用都将记录到 SLF4J。