首先,從一個簡單的註解開始,@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
String value() default "";
}
使用javap -verbose命令檢視這個註解的class檔案,發現這個註解被編譯成了介面,並且繼承了java.lang.annotation.Annotation介面,介面是不能直接例項化使用的,當在程式碼中使用這個註解,並使用getAnnotation方法獲取註解資訊時,JVM透過動態代理的方式生成一個實現了Test介面的代理物件例項,然後對該例項的屬性賦值,value值就存在這個代理物件例項中。
如果順著getAnnotation方法繼續跟蹤原始碼,會發現建立代理物件是在AnnotationParser.java中實現的,這個類中有一個annotationForMap方法。在annotationForMap方法內部使用Proxy.newProxyInstance方法在執行時動態建立代理,AnnotationInvocationHandler實現了InvocationHandler介面,當呼叫代理物件的value()方法獲取註解的value值,就會進入AnnotationInvocationHandler類中的invoke方法,深入invoke方法會發現,獲取value值最終是從AnnotationInvocationHandler類的memberValues屬性中獲取的,memberValues是一個Map型別,key是註解的屬性名,這裡就是“value”,value是使用註解時設定的值。
首先,從一個簡單的註解開始,@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
String value() default "";
}
使用javap -verbose命令檢視這個註解的class檔案,發現這個註解被編譯成了介面,並且繼承了java.lang.annotation.Annotation介面,介面是不能直接例項化使用的,當在程式碼中使用這個註解,並使用getAnnotation方法獲取註解資訊時,JVM透過動態代理的方式生成一個實現了Test介面的代理物件例項,然後對該例項的屬性賦值,value值就存在這個代理物件例項中。
如果順著getAnnotation方法繼續跟蹤原始碼,會發現建立代理物件是在AnnotationParser.java中實現的,這個類中有一個annotationForMap方法。在annotationForMap方法內部使用Proxy.newProxyInstance方法在執行時動態建立代理,AnnotationInvocationHandler實現了InvocationHandler介面,當呼叫代理物件的value()方法獲取註解的value值,就會進入AnnotationInvocationHandler類中的invoke方法,深入invoke方法會發現,獲取value值最終是從AnnotationInvocationHandler類的memberValues屬性中獲取的,memberValues是一個Map型別,key是註解的屬性名,這裡就是“value”,value是使用註解時設定的值。