作者舉了一些例子來解釋何為靜態(tài)Proxy,何為動態(tài)Proxy。奈何我根基尚淺,最作者舉的動態(tài)Proxy的例子懵懂不解,于是自己嘗試著摸索一番,終于對動態(tài)Proxy的用法有了一個初步的認識。
首先還是來看靜態(tài)Proxy,就我目前的認識看來,Proxy的主要用途是對類中方法的執(zhí)行進行一下包裝,在方法執(zhí)行之前,或之后,或both,加入一些“額外”的操作。典型的應(yīng)用就是加入事務(wù)處理。
靜態(tài)Proxy相對來講比較簡單,它是對上面所述思想的一個最直接的實現(xiàn)。
假設(shè)我們現(xiàn)在有如下一個接口:





以及該接口的一個實現(xiàn)類:










那么很容易,我們可以通過如下方式進行調(diào)用:















輸出結(jié)果:

現(xiàn)在問題來了:如果現(xiàn)在我們想在getMessage()之外添加一些額外的操作,比如在這之前輸出“Begin”,在之后輸出“done”,但又不能改變原有接口,怎么辦?也很簡單,用靜態(tài)Proxy就可以很方便的實現(xiàn):



















調(diào)用:














結(jié)果:




你可以看到,StaticProxy只是在Foo的某實現(xiàn)類基礎(chǔ)上包了一層,當(dāng)然我們這里加的兩個輸出語句無足輕重,但如果我們把這兩個輸出語句替換成事務(wù)處理,意義就大不一樣了。
可見,通過靜態(tài)Proxy可以實現(xiàn)我們的需求,但如果我們有十幾、二十個這樣的接口實現(xiàn)類,需要類似的處理,我們怎么辦?難道每個實現(xiàn)類都對應(yīng)一個Proxy嗎?
這時,我們就需要動態(tài)Proxy:





























第一次看到上面的代碼肯定不知所以,稍后解釋,我們先看如何調(diào)用:


















結(jié)果:





下面來解釋一下AOPHandler這個類:
首先,bind()方法是用來創(chuàng)建動態(tài)Proxy實例。動態(tài)Proxy也是Proxy,和靜態(tài)Proxy一樣,功能上都是為了在調(diào)用某接口實現(xiàn)類的方法之余,添加一些額外的操作(比如事務(wù)處理),他們(動態(tài)和靜態(tài)Proxy)都是一種特殊的接口實現(xiàn)類。因此,我們在調(diào)用的時候可以用
String message = ((Foo) proxy).getMessage("Wing");
把proxy實例直接cast為Foo類型,并調(diào)用foo接口上的方法。
不同的是,靜態(tài)Proxy,正如前面看到的,是直接實現(xiàn)了接口,并在接口的方法中直接調(diào)用該接口某實現(xiàn)類對應(yīng)的方法。而動態(tài)Proxy,是利用Java.lang.reflect.Proxy類提供的這樣一種機制:當(dāng)構(gòu)建Proxy時,我們需要提供接口,以及一個關(guān)聯(lián)的調(diào)用處理程序?qū)ο螅ㄍǔ崿F(xiàn)了InvocationHandler接口),當(dāng)我們在Proxy上調(diào)用接口上的方法(任意方法)時,將觸發(fā)調(diào)用InvocationHandler接口定義的invoke()方法,由invoke方法完成相應(yīng)的操作。
上面的AOPHandler類,是將動態(tài)Proxy的構(gòu)建與InvocationHandler接口的實現(xiàn)結(jié)合在了一起。
通過AOPHandler,我們可以在運行時期動態(tài)的決定用哪個接口實現(xiàn)類來創(chuàng)建Proxy,而不需事先為每個實現(xiàn)類定義對應(yīng)的Proxy,靈活性和復(fù)用性大大增強。
進一步的,我們可以利用java反射機制,通過類名來得到接口實現(xiàn)類的實例,進而得到該實例的動態(tài)Proxy。這樣我們就可以在配置文件里動態(tài)指定需要用到的接口實現(xiàn)類,就像Spring中所做的一樣。