2012-08-26 39 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

這應該真的是被接受的答案。比上面簡單得多。 –