詳解Java Cglib動(dòng)態(tài)代理
今天來介紹另一種更為強(qiáng)大的代理——Cglib動(dòng)態(tài)代理。
什么是Cglib動(dòng)態(tài)代理?
我們先回顧一下上一篇的jdk動(dòng)態(tài)代理,jdk動(dòng)態(tài)代理是通過接口來在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建委托類的代理對(duì)象,但是跟靜態(tài)代理一樣有一個(gè)缺點(diǎn),就是必須和委托類實(shí)現(xiàn)相同的接口,當(dāng)接口數(shù)量增加時(shí),便需要增加代理類的數(shù)量才能滿足需求,而且如果委托類是別人寫的,而且沒有實(shí)現(xiàn)任何接口,那么jdk動(dòng)態(tài)代理就有些力不從心了。
這時(shí)候Cglib動(dòng)態(tài)代理就脫穎而出了,Cglib并不依賴接口,可以直接生成委托類的代理對(duì)象,而且可以代理委托類的任意非final修飾的public和protected方法,我們可以先來看一個(gè)栗子。
先定義一個(gè)Programmer類:
public class Programmer {
private String name;
public void setName(String name) { System.out.println("Setting Name.");
this.name = name;
}public void code(){
System.out.println(name + " is writing bugs.");
}
}
然后定義一個(gè)代理類:
public class ProgrammerProxy implements MethodInterceptor {
/**
* 內(nèi)部持有委托類對(duì)象的引用
*/
private Object target;
/**
* 創(chuàng)建代理類對(duì)象
*/
public Programmer createProxy(Programmer object){
target = object;
//創(chuàng)建Enhancer對(duì)象
Enhancer enhancer = new Enhancer();
//設(shè)置要代理的目標(biāo)類,以擴(kuò)展功能
enhancer.setSuperclass(this.target.getClass());
//設(shè)置單一回調(diào)對(duì)象,在回調(diào)中攔截對(duì)目標(biāo)方法的調(diào)用
enhancer.setCallback(this);
//設(shè)置類加載器
enhancer.setClassLoader(object.getClass().getClassLoader());
//創(chuàng)建代理對(duì)象
return (Programmer)enhancer.create();
}
/**
* 回調(diào)方法:在代理實(shí)例上攔截并處理目標(biāo)方法的調(diào)用,返回結(jié)果
* @param proxy 代理類
* @param method 被代理的方法
* @param params 該方法的參數(shù)數(shù)組
* @param methodProxy
*/
@Override
public Object intercept(Object proxy, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
//調(diào)用之前處理
doBefore();
//調(diào)用原方法
method.invoke(target,params);
//調(diào)用之后處理
doAfter();
return null;
}
private void doAfter() {
System.out.println("do after.");
}
private void doBefore() {
System.out.println("do before.");
}
}
然后測試一下:
public class ProxyTest {
@Test
public void testCglibProxy(){
//創(chuàng)建一個(gè)Programmer對(duì)象
Programmer programmerA = new Programmer();
programmerA.setName("Frank");
//創(chuàng)建代理對(duì)象
Programmer programmerProxyA = new ProgrammerProxy().createProxy(programmerA);
programmerProxyA.code();
//修改代理對(duì)象
programmerProxyA.setName("Wang");
programmerProxyA.code();
//修改委托類對(duì)象
programmerA.setName("Song");
programmerProxyA.code();
}
}
輸出如下:
Setting Name.
do before.
Frank is writing bugs.
do after.
do before.
Setting Name.
do after.
do before.
Wang is writing bugs.
do after.
Setting Name.
do before.
Song is writing bugs.
do after.
Cglib實(shí)現(xiàn)動(dòng)態(tài)代理的步驟也不是很麻煩,先創(chuàng)建一個(gè)類實(shí)現(xiàn)MethodInterceptor接口,重寫intercept方法,在intercep中可以截獲委托類的所有非final修飾的public和protected方法,上例中,method.invoke(target,params);即為調(diào)用原對(duì)象的原方法,在代理類中保存了委托類對(duì)象的引用,這一點(diǎn)跟JDK動(dòng)態(tài)代理是一樣的。在調(diào)用原方法前先調(diào)用了doBefore方法,調(diào)用之后還調(diào)用了doAfter方法,從而實(shí)現(xiàn)了代理功能。至于createProxy方法,也只是一個(gè)固定步驟,先創(chuàng)建Enhance對(duì)象,然后將委托類的一些屬性往里塞,然后調(diào)用create方法來動(dòng)態(tài)生成代理對(duì)象。
在測試類中,為了更明顯的說明代理類與委托類的關(guān)系,分別用代理類對(duì)象programmerProxyA和委托類對(duì)象programmerA對(duì)name字段進(jìn)行修改,可以產(chǎn)生一樣的效果。
下面來對(duì)比一下Cglib動(dòng)態(tài)代理與JDK動(dòng)態(tài)代理:
1.兩者都是動(dòng)態(tài)代理,都是運(yùn)行時(shí)動(dòng)態(tài)生成代理對(duì)象。
2.JDK動(dòng)態(tài)代理利用的是接口信息來實(shí)現(xiàn)的代理,委托類必須實(shí)現(xiàn)某個(gè)或者某些接口,而Cglib則是利用繼承關(guān)系,利用asm在運(yùn)行時(shí)動(dòng)態(tài)生成委托類的子類,從而實(shí)現(xiàn)對(duì)委托類的代理。因此不依賴接口。
3.Cglib由于是利用繼承關(guān)系來實(shí)現(xiàn)代理的,因此無法代理被final修飾的類以及被final修飾的方法。
4.Cglib一般來說效率要比JDK動(dòng)態(tài)代理效率更高,可以實(shí)現(xiàn)的代理也更為強(qiáng)大。
當(dāng)然,具體情況具體分析,雖然Cglib比Jdk動(dòng)態(tài)代理更強(qiáng)大,但并不一定各個(gè)地方都強(qiáng)行使用,有時(shí)候JDK動(dòng)態(tài)代理相對(duì)來說更加簡單粗暴。
至此,本篇完結(jié),代理相關(guān)內(nèi)容講解完畢,歡迎大家繼續(xù)關(guān)注。
jar包下載地址:http://www.dhdzp.com/softs/570453.html
以上就是詳解Java Cglib動(dòng)態(tài)代理的詳細(xì)內(nèi)容,更多關(guān)于Java Cglib動(dòng)態(tài)代理的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JAVA的Dubbo如何實(shí)現(xiàn)各種限流算法
Dubbo是一種高性能的Java RPC框架,廣泛應(yīng)用于分布式服務(wù)架構(gòu)中,在Dubbo中實(shí)現(xiàn)限流可以幫助服務(wù)在高并發(fā)場景下保持穩(wěn)定性和可靠性,常見的限流算法包括固定窗口算法、滑動(dòng)窗口算法、令牌桶算法和漏桶算法,在Dubbo中集成限流器可以通過實(shí)現(xiàn)自定義過濾器來實(shí)現(xiàn)2025-01-01
@Value如何獲取yml和properties配置參數(shù)
這篇文章主要介紹了@Value如何獲取yml和properties配置參數(shù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
解決idea中javaweb的mysql8.0.15配置問題
這篇文章主要介紹了idea中javaweb的mysql8.0.15配置問題 ,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-05-05
Mybatis日志參數(shù)快速替換占位符工具的詳細(xì)步驟
這篇文章主要介紹了Mybatis日志參數(shù)快速替換占位符工具的詳細(xì)步驟,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08

