Java 注解原理


下面來看看Java中注解是如何實現的

創建注解類Inter:

Java 注解原理

 

創建測試類Test:

Java 注解原理

 

在程序第二句設置斷點,可以看到:

Java 注解原理

 

可以看到,注解的實例是一個動態代理類的對象.

要想查看這個動態代理類,可以在代碼中加

System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

添加系統代理,將其導出為class文件

Java 注解原理

 

可以看到如下兩個文件:

Java 注解原理

 

反編譯$Proxy1.class,如下:

Java 注解原理

 

可以看到,動態代理類是我們定義的注解實現類,反編譯Inner.class,如下:

Java 注解原理

 

可以看到,注解接口繼承了java.lang.annotation.Annotation, 通過查看源碼,該類源碼如下:

Java 注解原理

 

可以看到, 該類下的方法都被$Proxy1動態代理類實現了.

到此處,我們已經知道Inner注解(接口)是一個繼承了Annotation接口的特殊接口,而我們通過反射獲取注解時,返回的是Java運行時生成的動態代理對象$Proxy1,該類就是Inner注解(接口)的具體實現類。

那么, 代理類是如何處理方法的調用的呢?

我們知道, 動態代理方法的調用最終會傳遞給綁定的InvocationHandler實例的invoke方法處理。我們可以看看$Proxy1的源碼

Java 注解原理

 

其中語句調用了父類的成員變量,其父類為Proxy, 查看該成員變量,如下:

Java 注解原理

 

可以看到, h對象類型就是InvocationHandler接口的某個實現類

我們在Proxy類的構造方法處設置斷點:

Java 注解原理

 

通過斷點可以查看h具體是哪個對象:

Java 注解原理

 

可以看到, 該動態代理類為AnnotationInvocationHandler對象, 查看該類的invoke方法如下:

Java 注解原理

 

其中的memberValues變量是以方法名為key,以變量為value的, 如下:

Java 注解原理

 

那么,這個memberValues變量是從哪來的呢?

Java 注解原理

 

可以看到,其是在構造函數中進行設置的.

反編譯我們的Test類,看到:

Java 注解原理

 

所以中間有一個類,負責創建代理對象AnnotationInvocationHandler, 其將變量從常量池中取出並創建map, 進而創建代理對象, 這個類就是 AnnotationParser, 在此不細說了, 感興趣的可以自行斷點調試查看.


總結

注解本質是一個繼承了Annotation的特殊接口,其具體實現類是Java運行時生成的動態代理類。通過代理對象調用自定義注解(接口)的方法,會最終調用AnnotationInvocationHandler的invoke方法。該方法會從memberValues這個Map中索引出對應的值。而memberValues的來源是Java常量池。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM