動態(tài)代理是指代理類對象在程序運行時由JVM根據(jù)反射機制動態(tài)生成的。動態(tài)代理不需要定義代理類的.java源文件。
動態(tài)代理其實就是jdk運行期間,動態(tài)創(chuàng)建class字節(jié)碼并加載到JVM。
動態(tài)代理的實現(xiàn)方式常用的有兩種:使用JDK代理代理,與通過CGLIB動態(tài)代理。
jdk動態(tài)代理是基于Java的反射機制實現(xiàn)的。使用jdk中接口和類實現(xiàn)代理對象的動態(tài)創(chuàng)建。
Jdk的動態(tài)要求目標對象必須實現(xiàn)接口,這是java設計上的要求。
從jdk1.3以來,java語言通過java.lang.reflect包提供三個類支持代理模式Proxy, Method和InovcationHandler。
⒈ InvocationHandler接口
InvocationHandler接口叫做調用處理器,負責完調用目標方法,并增強功能。
通過代理對象執(zhí)行目標接口中的方法,會把方法的調用分派給調用處理器(InvocationHandler)的實現(xiàn)類,執(zhí)行實現(xiàn)類中的invoke()方法,我們需要把功能代理寫在invoke()方法中 。

接口中只有一個方法:

在invoke方法中可以截取對目標方法的調用。在這里進行功能增強。Java的動態(tài)代理是建立在反射機制之上的。
實現(xiàn)了InvocationHandler接口的類用于加強目標類的主業(yè)務邏輯。這個接口中有一個方法invoke(),具體加強的代碼邏輯就是定義在該方法中的。通過代理對象執(zhí)行接口中的方法時,會自動調用invoke()方法。
invoke()方法的介紹如下:
public Object invoke ( Object proxy, Method method, Object[] args)
proxy:代表生成的代理對象
method:代表目標方法
args:代表目標方法的參數(shù)
第一個參數(shù)proxy是jdk在運行時賦值的,在方法中直接使用,第二個參數(shù)后面介紹,第三個參數(shù)是方法執(zhí)行的參數(shù), 這三個參數(shù)都是jdk運行時賦值的,無需程序員給出。
⒉Method 類
invoke()方法的第二個參數(shù)為Method類對象,該類有一個方法也叫invoke(),可以調用目標方法。這兩個invoke()方法,雖然同名,但無關。
public Object invoke ( Object?obj, Object...?args)
obj:表示目標對象
args:表示目標方法參數(shù),就是其上一層invoke方法的第三個參數(shù)
該方法的作用是:調用執(zhí)行obj對象所屬類的方法,這個方法由其調用者Method對象確定。
在代碼中,一般的寫法為method.invoke(target, args);其中,method為上一層invoke方法的第二個參數(shù)。這樣,即可調用了目標類的目標方法。
⒊Proxy類
通過JDK的java.lang.reflect.Proxy類實現(xiàn)動態(tài)代理,會使用其靜態(tài)方法newProxyInstance(),依據(jù)目標對象、業(yè)務接口及調用處理器三者,自動生成一個動態(tài)代理對象。
public static newProxyInstance ( ClassLoader loader, Class<?>[] interfaces,
InvocationHandler handler)
loader:目標類的類加載器,通過目標對象的反射可獲取
interfaces:目標類實現(xiàn)的接口數(shù)組,通過目標對象的反射可獲取
handler:調用處理器。
jdk動態(tài)代理實現(xiàn)
jdk動態(tài)代理是代理模式的一種實現(xiàn)方式,其只能代理接口。
實現(xiàn)步驟:
① 新建一個接口,作為目標接口
② 為接口創(chuàng)建一個實現(xiàn)類,是目標類
③ 創(chuàng)建類實現(xiàn)java.lang.reflect.InvocationHandler接口,調用目標方法并增加其他功能代碼
④ 創(chuàng)建動態(tài)代理對象,使用Proxy.newProxyInstance()方法,并把返回值強制轉為接口類型。
idea創(chuàng)建java project
工程名稱:ch02-dynamicproxy
⒈定義目標接口

⒉定義目標接口實現(xiàn)類

⒊定義調用處理程序
調用處理程序是實現(xiàn)了InvocationHandler的類,在invoke方法中增加業(yè)務功能。還需要創(chuàng)建有參構造,參數(shù)是目標對象。為的是完成對目標對象的方法調用。

⒋創(chuàng)建動態(tài)代理對象

執(zhí)行流程:

類圖:

CGLIB(Code Generation Library)是一個開源項目。是一個強大的,高性能,高質量的Code生成類庫,它可以在運行期擴展Java類與實現(xiàn)Java接口。它廣泛的被許多AOP的框架使用,例如Spring AOP。
使用JDK的Proxy實現(xiàn)代理,要求目標類與代理類實現(xiàn)相同的接口。若目標類不存在接口,則無法使用該方式實現(xiàn)。
但對于無接口的類,要為其創(chuàng)建動態(tài)代理,就要使用CGLIB來實現(xiàn)。CGLIB代理的生成原理是生成目標類的子類,而子類是增強過的,這個子類對象就是代理對象。所以,使用CGLIB生成動態(tài)代理,要求目標類必須能夠被繼承,即不能是final的類。
cglib經(jīng)常被應用在框架中,例如Spring ,Hibernate等。Cglib的代理效率高于Jdk。對于cglib一般的開發(fā)中并不使用。做了一個了解就可以。