Java Annotation 機制源碼分析與使用

1 Annotationhtml

1.1 Annotation 概念及做用java

     1.  概念數組

  An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct effect on the operation of the code they annotate.[3]安全

  可以添加到 Java 源代碼的語法元數據。類、方法、變量、參數、包均可以被註解,可用來將信息元數據與程序元素進行關聯。oracle

  更直觀的理解,它提供了一種安全的相似註釋的機制,用來將任何的信息或元數據(metadata)與程序元素(類、方法、成員變量等)進行關聯。less

     2.  定義    ide

   Annotation經過以下的方式進行定義函數

public @interface Override {
}

  其中的@interface是一個關鍵字,這個關鍵字聲明隱含了一個信息:它是繼承了java.lang.annotation.Annotation接口,並不是聲明瞭一個interface。在設計annotations的時候必須把一個類型定義爲@interface,而不能用class或interface關鍵字。定義的詳細內容參考[1.2.3]自定義Annotation一節。ui

  3.  做用this

  Annotation的引入是爲了從Java語言層面上,爲Java源代碼提供元數據的支持

    (1).   標記,用於告訴編譯器一些信息

    Marker Annotation:該Annotation沒有參數輸入,更多相似於標識一個東西,相似於Java語言中的java.io.Serialable之類的接口,並沒有須要實現的方法。

    (2).   編譯時動態處理,如動態生成代碼

    (3).   運行時動態處理,如獲得註解信息

1.2  Annotation 分類

1.2.1    標準 Annotation

      1.     @Override

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

   2.     @Deprecated

@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Deprecated {
}

   3.    @SuppressWarnings

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

  標準Annotation是指Java自帶的幾個Annotation,上面三個分別表示重寫函數,函數已經被禁止使用,忽略某項Warning

1.2.2    元 Annotation

 元Annotation是指用來定義Annotation的Annotation

     1.   @Retention

 @Retention表示Annotation做用範圍和保留時間,可選值SOURCE(源碼時),CLASS(編譯時),RUNTIME(運行時),默認爲 CLASS,值爲 SOURCE 大都爲Mark   Annotation,這類Annotation 大都用來校驗,好比Override, SuppressWarnings

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    RetentionPolicy value();
}
public enum RetentionPolicy {
    /* Annotations are to be discarded by the compiler. */
    SOURCE,
    /* Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior. */
    CLASS,
    /* Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     * @see java.lang.reflect.AnnotatedElement */
    RUNTIME
}

   2.     @Target

  @Target 表示Annotation能夠用來修飾哪些程序元素,如 TYPE, METHOD, CONSTRUCTOR, FIELD, PARAMETER 等,未標註則表示可修飾全部

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    ElementType[] value();
}
public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,
    /** Field declaration (includes enum constants) */
    FIELD,
    /** Method declaration */
    METHOD,
    /** Parameter declaration */
    PARAMETER,
    /** Constructor declaration */
    CONSTRUCTOR,
    /** Local variable declaration */
    LOCAL_VARIABLE,
    /** Annotation type declaration */
    ANNOTATION_TYPE,
    /** Package declaration */
    PACKAGE
}

   3.     @Inherited[4][5]

  @Inherited 表示父類Annotation能夠被子類繼承

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

  @Inherited標識某個被標註的類型是被繼承的。使用了@Inherited修飾的annotation類型被用於一個class之時,則這個annotation將被用於該class的相應子類。

  注意:@Inherited annotation類型是被標註過的class的子類所繼承。類並不從它所實現的接口繼承annotation,方法並不從它所重載的方法繼承annotation。

   當@Inherited annotation類型標註的annotation的Retention是RetentionPolicy.RUNTIME,則反射API加強了這種繼承性。若是咱們使用java.lang.reflect去查詢一個  @Inherited annotation類型的annotation時,反射代碼檢查將展開工做:檢查class和其父類,直到發現指定的annotation類型被發現,或者到達類繼承結構的頂層。

  就是說, 查看查找@Inherited過的Annotation之時,須要反覆的向上查找,方纔能夠。

     4.     @Documented

  @Documented所修飾的Annotation連同自定義Annotation所修飾的元素一同保存到Javadoc文檔中

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

 1.2.3    自定義Annotation

  自定義Annotation表示本身根據須要定義的Annotation,定義時須要用到上面的元Annotation。這裏只是一種分類而已,也能夠根據做用域分爲源碼時、編譯時、運行時 Annotation。

  下面經過自定義Annotation MethodInfo,以實例來具體介紹自定義Annotation的使用。

   1.   自定義Annotation定義

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface MethodInfo {
     String author() default "trinea@gmail.com";
     String date();
     int version() default 1;
}

  MethodInfo Annotation定義部分:

    (1)   經過@interface 定義,註解名即爲自定義註解名

    (2)   註解配置參數名爲註解類的方法名,且:

      a)   全部方法沒有方法體,方法名即爲屬性名,沒有參數沒有修飾符,實際只容許 public & abstract 修飾符,默認爲 public ,不容許拋異常

      b)  方法返回值只能是基本類型,String, Class, annotation, enumeration 或者是他們的一維數組,返回類型即爲屬性類型

      c)  若只有一個默認屬性,可直接用 value() 函數。一個屬性都沒有表示該 Annotation 爲 Mark Annotation

      d)  能夠加 default 表示默認值,null不能做爲成員默認值

    2.      自定義Annotation調用

public class App {
    @MethodInfo( author =「xiaotian」, date="2014/02/14", version=2)
    public String getAppName() {
        return "trinea";
    }
}

這裏是調用自定義Annotation--MethodInfo的示例,MethodInfo Annotation 做用爲給方法添加相關信息,包括 author、date、version

    3.   運行時Annotation解析

    (1).   Annotation解析API

  運行時Annotation指@Retention爲RUNTIME的Annotation,可手動調用下面經常使用 API 解析。

public interface AnnotatedElement {
    /* Returns true if an annotation for the specified type
     * is present on this element, else false.  This method
     * is designed primarily for convenient access to marker annotations.*/
   boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);

    /* Returns this element's annotation for the specified type if
     * such an annotation is present, else null */
   <T extends Annotation> T getAnnotation(Class<T> annotationClass);

    /* Returns all annotations present on this element.  (Returns an array
     * of length zero if this element has no annotations.)  The caller of
     * this method is free to modify the returned array; it will have no
     * effect on the arrays returned to other callers */
    Annotation[] getAnnotations();

    /* Returns all annotations that are directly present on this
     * element.  Unlike the other methods in this interface, this method
     * ignores inherited annotations.  (Returns an array of length zero if
     * no annotations are directly present on this element.)  The caller of
     * this method is free to modify the returned array; it will have no
     * effect on the arrays returned to other callers */
    Annotation[] getDeclaredAnnotations();

}

  其中Constructor,Field,Method都繼承類class AccessibleObject implements AnnotatedElement;可經過以下接口來解析annotation:

  • element.getAnnotation(AnnotationName.class):

  表示獲得element某個 AnnotationName的信息,由於一個 Target 能夠被多個 Annotation 修飾

  •  element.getAnnotations( ) :

  則表示獲得element全部Annotations

  • element.isAnnotationPresent(AnnotationName.class):

  表示該元素是否被某個 AnnotationNam修飾

  (2).    App解析實例分析

public static void main(String[] args) {
    try {
        Class cls = Class.forName("java.test.annotation.App");
        for (Method method : cls.getMethods()) {
            MethodInfo methodInfo = method.getAnnotation(MethodInfo.class);
            if (methodInfo != null) {
                System.out.println("method name:" + method.getName());
                System.out.println("method author:" + methodInfo.author());
                System.out.println("method version:" + methodInfo.version());
                System.out.println("method date:" + methodInfo.date());
            }
        }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

  以上解析代碼以MethodInfo Annotation爲例,利用 Target(這裏是 Method)getAnnotation函數獲得Annotation信息,而後就能夠調用Annotation的方法獲得響應屬性值

  4.      編譯時Annotation解析

    (1).     編譯時Annotation解析過程

  編譯時Annotation指@Retention爲CLASS 的Annotation,由apt(Annotation Processing Tool) 解析自動解析。

  須要作的

      a)   自定義類集成自AbstractProcessor

      b)   重寫其中的 process 函數

      實際是 apt(Annotation Processing Tool) 在編譯時自動查找全部繼承自 AbstractProcessor 的類,而後調用他們的 process 方法去處理

    (2).     解析示例

  假設以前自定義的MethodInfo的@Retention爲CLASS,

@SupportedAnnotationTypes({ " java.test.annotation.MethodInfo" })
public class MethodInfoProcessor extends AbstractProcessor {
     @Override
    public boolean process(Set<?extends TypeElement> annotations, RoundEnvironment env) {
        HashMap<String, String> map = new HashMap<String, String>();
        for (TypeElement te : annotations) {
            for (Element element : env.getElementsAnnotatedWith(te)) {
                MethodInfo methodInfo = element.getAnnotation(MethodInfo.class);
                map.put(element.getEnclosingElement().toString(), methodInfo.author());
            }
        }
        return false;
    }
}

  SupportedAnnotationTypes表示這個Processor要處理的Annotation 名字。process函數中參數annotations表示待處理的 Annotations,參數 env 表示當前或是以前的運行環境, process函數返回值表示這組annotations是否被這個 Processor 接受,若是接受後續子的 rocessor不會再對這個Annotations 進行處理。

  

參考

[1].    The Java™ Tutorials : http://docs.oracle.com/javase/tutorial/java/annotations/

[2].   APT: Compile-Time Annotation Processing with Java

http://www.javalobby.org/java/forums/t17876.html

[3].   Java annotation : http://en.wikipedia.org/wiki/Java_annotation

[4].     Java中@Inherited註解的運用: http://xiangdefei.iteye.com/blog/1044199

[5].   Annotation Inheritance Examples: http://www.jroller.com/alessiopace/entry/annotation_inheritance_examples

相關文章
相關標籤/搜索