Java高級編程細節-動態代理-進階高級開發必學技能

關於代理模式的話題有很多,

在開發中經常用到的應該是靜態代理模式,能很好的去耦合。

動態代理是代理模式的另外一種實現。

動態代理的區別在哪裡?

動態代理有什麼好處?

今天我們來分析下這些問題。

回顧靜態代理

之前我們分析過一次靜態代理,

用代理模式優雅地寫代碼

一個典型的代理模式的 Proxy類像下面這樣,

Java高級編程細節-動態代理-進階高級開發必學技能

對於調用者來說,需要把構造好的實例傳給代理,然後就可以用代理來替代操作真正的實例了。

靜態代理的問題是,

在接口代碼少的情況下一切沒什麼問題,但是當接口增加的時候,

Proxy 類就需要響應的增加接口,比方上面的 Func 接口,

Java高級編程細節-動態代理-進階高級開發必學技能

剛開始可能只有一個 read()方法,後面慢慢發展到有了 write(),有了 mark(),

隨著接口量的增加, Proxy的維護工作量也在逐步增加。

那麼動態代理能怎麼解決這種問題呢?

動態代理的實現

動態代理的實現步驟基本如下:

· 定義一個公共接口(像 Func)和實現類(像 User),這部分跟靜態代理一樣

· 定義一個 DynamicProxy類實現 InvocationHandler 接口,這個Proxy類似於靜態代理的 Proxy然而不用實現 Func接口

· 調用 Proxy類來構造代理對象

在動態代理的實現中有兩個東西非常重要,一個是 Proxy類,一個是 InvocationHandler接口,都位於 reflect包下,

我們來看第二個步驟所定義的 DynamicProxy是怎樣的吧

Java高級編程細節-動態代理-進階高級開發必學技能

它同樣持有了委託對象實例,但是和靜態代理不同,

它並沒有實現委託對象的接口方法,

而只實現了 InvocationHandler的 invoke方法,然後調用了 method.invoke(this.user, objects);

可以留意下 invoke方法,後面我們繼續分析,

這裡再貼一下 Client類的代碼,也就是使用 Proxy的地方,

Java高級編程細節-動態代理-進階高級開發必學技能

跟靜態代理不同的地方在於,雖然這裡也需要實例化一個委託類的對象,並傳給 Proxy的構造方法,

但這裡所實例化的是 InvocationHandler對象,而不是 DynamicProxy的對象。

到這裡就完成了一個動態代理的代碼,輸出結果如下

before invoke user method

user read

after invoke user method

比較&分析

· 先來說第二個步驟的 DynamicProxy的實現,

可以發現跟靜態代理不同的地方在於,靜態代理需要實現 Func接口的 read()方法,而動態代理實現的是 InvocationHandler的 invoke方法,

靜態代理需要在不同的接口中去調用 User 接口的不同方法,

而動態代理在invoke被調用的過程中不需要關心需要調用 User 的哪個具體方法,

方法被封裝在 method對象中,而所需要的參數則在 Object[] objects,

直接調用就可以

Java高級編程細節-動態代理-進階高級開發必學技能

這裡就意味著即使以後增加了 Func的接口,對於 DynamicProxy來說也不需要增加額外的維護量。

· Proxy.newProxyInstance幹了什麼

在靜態代理裡面,我們會直接用 new StaticProxy(user)構造出來的靜態對象直接操作,

而在動態代理裡面,我們操作的是 Proxy.newProxyInstance所構造出來的動態代理對象 proxyUser,

可能初次接觸動態代理的同學在這裡就概念混亂了,

"難道代理類不是 new DynamicProxy出來的對象嗎?"

其實不是的,如果把 proxyUser的類名打印出來的話,

它會以 $ProxyN的形式存在,N從0開始,這個就是動態代理所生成的真正代理對象,

動態代理的意義就在於這裡,$ProxyN 這個對象是在運行時創建的,

如果用代碼來解釋的話,$ProxyN的代碼會像下面這樣

Java高級編程細節-動態代理-進階高級開發必學技能

這個才是真正的代理類。


分享到:


相關文章: