37

爪哇大师,

我对这个很陌生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 {
    //....
}   

我能得到一些提示吗?

4

3 回答 3

46

根据您对我的评论的回答,您将无法仅使用注释来执行此操作。当然,您可以创建注释并创建一些反射代码,然后检测并执行一些代码,但这不会对您的代码进行太多更改,因为您需要在调用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:具有日志静态方法的类(这将执行“解析”)

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:

于 2012-08-26T14:24:51.630 回答
26

将 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
     }
    
于 2016-04-04T12:10:51.280 回答
3

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

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

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

于 2013-02-03T08:16:12.047 回答