Java JDK 動態代理使用及實現原理分析

http://blog.jobbole.com/104433/

1、什麼是代理?

代理是一種經常使用的設計模式,其目的就是爲其餘對象提供一個代理以控制對某個對象的訪問。代理類負責爲委託類預處理消息,過濾消息並轉發消息,以及進行消息被委託類執行後的後續處理。java

代理模式UML圖:git

爲了保持行爲的一致性,代理類和委託類一般會實現相同的接口,因此在訪問者看來二者沒有絲毫的區別。經過代理類這中間一層,能有效控制對委託類對象的直接訪問,也能夠很好地隱藏和保護委託類對象,同時也爲實施不一樣控制策略預留了空間,從而在設計上得到了更大的靈活性。Java 動態代理機制以巧妙的方式近乎完美地實踐了代理模式的設計理念。github

2、Java 動態代理類

Java動態代理類位於java.lang.reflect包下,通常主要涉及到如下兩個類:設計模式

(1)Interface InvocationHandler:該接口中僅定義了一個方法數組

[java] view plain copy緩存

  1. publicobject invoke(Object obj,Method method, Object[] args)

在實際使用時,第一個參數obj通常是指代理類,method是被代理的方法,如上例中的request(),args爲該方法的參數數組。這個抽象方法在代理類中動態實現。app

(2)Proxy:該類即爲動態代理類,其中主要包含如下內容:ide

protected Proxy(InvocationHandler h):構造函數,用於給內部的h賦值。函數

static Class getProxyClass (ClassLoaderloader, Class[] interfaces):得到一個代理類,其中loader是類裝載器,interfaces是真實類所擁有的所有接口的數組。工具

static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h):返回代理類的一個實例,返回後的代理類能夠看成被代理類使用(可以使用被代理類的在Subject接口中聲明過的方法)

所謂DynamicProxy是這樣一種class:它是在運行時生成的class,在生成它時你必須提供一組interface給它,而後該class就宣稱它實現了這些interface。你固然能夠把該class的實例看成這些interface中的任何一個來用。固然,這個DynamicProxy其實就是一個Proxy,它不會替你做實質性的工做,在生成它的實例時你必須提供一個handler,由它接管實際的工做。

在使用動態代理類時,咱們必須實現InvocationHandler接口

經過這種方式,被代理的對象(RealSubject)能夠在運行時動態改變,須要控制的接口(Subject接口)能夠在運行時改變,控制的方式(DynamicSubject類)也能夠動態改變,從而實現了很是靈活的動態代理關係。

動態代理步驟
1.建立一個實現接口InvocationHandler的類,它必須實現invoke方法
2.建立被代理的類以及接口
3.經過Proxy的靜態方法
newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)建立一個代理
4.經過代理調用方法

3、JDK的動態代理怎麼使用?

一、須要動態代理的接口:

 

 

二、須要代理的實際對象

 

 

三、調用處理器實現類

 

 

四、測試

 

 

五、輸出結果以下:

演示demo下載地址:http://download.csdn.net/detail/xunzaosiyecao/9597388

4、動態代理怎麼實現的?

從使用代碼中能夠看出,關鍵點在:

經過跟蹤提示代碼能夠看出:當代理對象調用真實對象的方法時,其會自動的跳轉到代理對象關聯的handler對象的invoke方法來進行調用。

 

也就是說,當代碼執行到:
subject.SayHello( 「jiankunking」)這句話時,會自動調用InvocationHandlerImpl的invoke方法。這是爲啥呢?
 
======橫線之間的是代碼跟分析的過程,不想看的朋友能夠直接看結論======
如下代碼來自:JDK1.8.0_92
既然生成代理對象是用的Proxy類的靜態方newProxyInstance,那麼咱們就去它的源碼裏看一下它到底都作了些什麼?
咱們再進去getProxyClass0方法看一下:

真相仍是沒有來到,繼續,看一下proxyClassCache

 

 

奧,原來用了一下緩存啊

那麼它對應的get方法啥樣呢?


咱們能夠看到它調用了 supplier.get(); 獲取動態代理類,其中supplier是Factory,這個類定義在WeakCach的內部。

 

來瞅瞅,get裏面又作了什麼?

發現重點仍是木有出現,但咱們能夠看到它調用了valueFactory.apply(key, parameter)方法:

 


經過看代碼終於找到了重點:

 


那麼接下來咱們也使用測試一下,使用這個方法生成的字節碼是個什麼樣子:

咱們用jd-jui 工具將生成的字節碼反編譯:

 


這就是最終真正的代理類,它繼承自Proxy並實現了咱們定義的Subject接口
也就是說:

 

這裏的subject實際是這個類的一個實例,那麼咱們調用它的:
就是調用咱們定義的InvocationHandlerImpl的 invoke方法:

======橫線之間的是代碼跟分析的過程,不想看的朋友能夠直接看結論=======

5、結論

到了這裏,終於解答了:
subject.SayHello(「jiankunking」)這句話時,爲何會自動調用InvocationHandlerImpl的invoke方法?

由於JDK生成的最終真正的代理類,它繼承自Proxy並實現了咱們定義的Subject接口,在實現Subject接口方法的內部,經過反射調用了InvocationHandlerImpl的invoke方法。

包含生成本地class文件的demo:http://download.csdn.net/detail/xunzaosiyecao/9597474

經過分析代碼能夠看出Java 動態代理,具體有以下四步驟:

    1. 經過實現 InvocationHandler 接口建立本身的調用處理器;
    2. 經過爲 Proxy 類指定 ClassLoader 對象和一組 interface 來建立動態代理類;
    3. 經過反射機制得到動態代理類的構造函數,其惟一參數類型是調用處理器接口類型;
    4. 經過構造函數建立動態代理類實例,構造時調用處理器對象做爲參數被傳入。
相關文章
相關標籤/搜索