歡迎光臨
每天分享高質量文章

純手寫實現JDK動態代理

(給ImportNew加星標,提高Java技能)

 

轉自:簡書,作者:張豐哲

www.jianshu.com/p/58759fef38b8

 

前言

 

在Java領域,動態代理應用非常廣泛,特別是流行的Spring/MyBatis等框架。JDK本身是有實現動態代理技術的,不過要求被代理的類必須實現介面,不過cglib對這一不足進行了有效補充。本篇部落格將涉及2個話題:第一,JDK動態代理的實現原理,帶你探索動態代理的實質面目;第二,自己動手寫程式碼去實現JDK動態代理,去創造世界!

 

JDK動態代理

 

先寫一個例子,感性認識下動態代理~

 

業務介面:

 

 

業務實現類:

 

 

業務處理類:

 

 

測試類:

 

 

執行結果:

 

 

在JDK動態代理中涉及如下角色:

 

業務介面Interface、業務實現類target、業務處理類Handler、JVM在記憶體中生成的動態代理類$Proxy0

 

動態代理原理圖:

 

 

說白了,動態代理的過程是這樣的:

 

  1. Proxy透過傳遞給它的引數(interfaces/invocationHandler)生成代理類$Proxy0;
  2. Proxy透過傳遞給它的引數(ClassLoader)來載入生成的代理類$Proxy0的位元組碼檔案;

 

我們來看看上面例子中生成的$Proxy0的模樣:

 

 

首先,$Proxy是實現了我們的業務介面(Man)的,所以客戶端顯然可以呼叫業務介面的方法。

 

其次,註意到$Proxy是繼承自Proxy,並透過構造方法將業務處理類傳入給父類Proxy進行初始化。(實質上,你可以看看原始碼,在Proxy中存在protected InvocationHandler h;)

 

初始化Proxy

 

 

findObject

 

 

很明顯,我們看到了業務介面的方法是如何被呼叫的:

 

最終都是回呼業務處理類(具體的Handler)的invoke方法完成呼叫!

 

手寫程式碼實現JDK動態代理

 

在上面,我們已經分析了JDK動態代理的整個呼叫過程,接下來,我們就來手寫實現它吧!

 

先來看一眼圖:

 

 

自定義InvocationHandler:

 

 

實現MyInvocationHandler的業務處理Handler:

 

 

自定義類載入器MyClassLoader:

 

 

為什麼要定義一個自定義的類載入器呢?它的作用是什麼呢?

 

要知道,我們是想手寫JDK動態代理,那麼我們將自己在記憶體中生成動態代理類,那麼我們如何載入呢?這時候,就可以利用自定義的類載入器做到!

 

上述程式碼,重寫了findClass方法,就是為了在指定路徑下載入指定的位元組碼檔案。

 

自定義MyProxy:

 

 

MyProxy的作用就相當於JDK的Proxy。MyProxy做了哪些事情呢?

 

  1. 需要根據interfaces介面構造出動態代理類需要的方法。(其實就是利用反射獲取)
  2. 把動態生成的代理類(即.java檔案)進行編譯,生成位元組碼檔案(即.class檔案),然後利用類載入進行載入
  3. 動態代理類進行載入後,利用反射機制,透過構造方法進行實體化,併在實體化時,初始化業務Hanlder

 

看一下MyProxy的其他方法:

 

編譯方法

 

 

getMethodString方法

 

 

執行結果

 

 

我們來看一眼生成的$MyProxy0:

 

 

OK,到這裡,整個JDK的動態代理的實現原理以及手寫實現就結束了,你學到了麼?

    贊(0)

    分享創造快樂