2012-08-26 37 views
15

的Java大师,自定义注释作为拦截器的方法记录

我为annotations很新,并没有搜索到了这个有很多,所以请多多包涵......

我想实施Custom Annotationintercept的方法调用;开始与一些非常基本的它可以只打印方法的名称和参数,这样我就能避免logger声明。

示例调用是这样的:

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

可以转化为:

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

我能得到这个一些提示?

+0

你想运行方法之前调试代码? – davidbuzatto

+0

在这种情况下是的。 – SiB

+0

好的。我忘了问。这个“之前”的执行需要在每个方法调用之前执行? – davidbuzatto

回答

29

根据你的我的意见的答案,你将不能够只用注释来做到这一点。你可以,当然,创建注释和创建将检测然后一些反射代码并执行一些代码,但是这不会改变你的代码太多,因为你将需要调用parser方法,你打电话给你的方法,我认为前这对你不会太有帮助,因为在每次调用之前你都需要调用解析器方法。

如果你需要,你提到的行为(自动呼叫),你需要向你的注解与像春天(普通Java)还是AspectJ(AspectJ的代码)一些AOP框架结合起来。随着时间的推移,你可以设置切入点,每次到达这个点时,都可以执行一些代码。您可以配置然后在方法执行之前和/或之后执行一些代码。

如果第一种情形是足够的,你可以这样做:

记录仪:枚举

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

    } 
} 
:与日志静态方法类(这将执行 “解析”)

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

当然,你将需要提高我的代码,以满足您的需求。这只是一个起点。

更多关于注解:

进一步了解AOP:

+0

+1。是的,请。在此先感谢 – SiB

+0

好的,代码是完整的。试一试;) – davidbuzatto

+0

我会;只要我进入办公室...... **非常感谢您为我写下这么好的回答所带来的所有痛苦! – SiB

1

前面已经提出,AOP和注释是最好的选择。我会建议使用从jcabi-aspects一个现成的机制(我是一个开发者):

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

所有的方法都将被记录到SLF4J。

9

使用Spring AOP和Java注释。 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 
    } 
    
+0

这应该真的是被接受的答案。比上面简单得多。 –