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

时间:2012-08-26 13:49:18

标签: java logging annotations interceptor

Java Gurus,

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

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

这样的示例调用:

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

可以转换为:

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

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

3 个答案:

答案 0 :(得分:36)

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

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

如果第一种情况足够,您可以执行以下操作:

记录器:枚举

public enum Logger {
    INFO,
    DEBUG;
}

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;

}

人:注释类

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:带有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;

            }

        }

    }

}

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

    }
}

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

有关注释的更多信息:

有关AOP的更多信息:

答案 1 :(得分:17)

使用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;
    }
    
  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
    }
    

答案 2 :(得分:3)

如前所述,AOP和注释是最佳选择。我建议使用jcabi-aspects(我是开发人员)的现成机制:

@Loggable(Loggable.DEBUG)
public String load(URL url) {
  return url.openConnection().getContent();
}

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