Java的CGLIB動態(tài)代理深入解析
一、介紹
CGLIB是強(qiáng)大的、高性能的代碼生成庫,被廣泛應(yīng)用于AOP框架,它底層使用ASM來操作字節(jié)碼生成新的類,為對象引入間接級別,以控制對象的訪問。
CGLIB相比于JDK動態(tài)代理更加強(qiáng)大,JDK動態(tài)代理只能對接口進(jìn)行代理,而CGLIB既可以代理普通類,也能夠代理接口。
優(yōu)點: 通過FastClass機(jī)制調(diào)用方法,比JDK動態(tài)代理的反射機(jī)制效率高;被代理類無需實現(xiàn)接口
缺點: 運(yùn)行期生成字節(jié)碼,通過ASM寫Class字節(jié)碼,效率低;不能對final類及final方法進(jìn)行代理
二、工作原理

CGLIB 通過動態(tài)生成一個需要被代理類的子類(即被代理類作為父類),該子類重寫被代理類的所有不是 final 修飾的方法,并在子類中采用方法攔截的技術(shù)攔截父類所有的方法調(diào)用,進(jìn)而織入橫切邏輯。此外,因為 CGLIB 采用整型變量建立了方法索引,這比使用 JDK 動態(tài)代理更快(使用 Java 反射技術(shù)創(chuàng)建代理類的實例)。
2.1步驟說明
生成代理對象 創(chuàng)建要被代理的類或接口–MyFly
public class MyFly implements Fly {
@Override
public void doFly() {
System.out.println("wo的");
}
}
實現(xiàn)MethodInterceptor并實現(xiàn)intercept方法 --CglibProxy
class CglibProxy implements MethodInterceptor {
/**
* @param o: 代理對象
* @param method: 被代理方法
* @param params: 方法入?yún)?
* @param methodProxy: CGLIB方法
**/
@Override
public Object intercept(Object o, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
System.out.println("【增強(qiáng)方法】代理對象正在執(zhí)行的方法:" + method.getName());
Object result = methodProxy.invokeSuper(o, params);
return result;
}
}
創(chuàng)建Enhancer(設(shè)置要被代理的類和調(diào)用方法時觸發(fā)的攔截器)
public static Object creatCglibProxyObj(Class<?> clazz) {
Enhancer enhancer = new Enhancer();
// 為加強(qiáng)器指定要代理的業(yè)務(wù)類(即為下面生成的代理類指定父類)
enhancer.setSuperclass(clazz);
// 設(shè)置回調(diào):對于代理類上所有方法的調(diào)用,都會調(diào)用CallBack,而Callback則需要實現(xiàn)intercept()方法
enhancer.setCallback(new CglibProxy());
return enhancer.create();
}
執(zhí)行程序
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");
Fly fly = (Fly) CglibProxyFactory.creatCglibProxyObj(MyFly.class);
fly.doFly();
}
結(jié)果:

2.2 代理對象分析
通過設(shè)置屬性來輸出生成的代理對象
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");

通過IDEA打開class文件
2.2.1表頭分析

結(jié)論: 生成的代理對象繼承了我們需要被代理的對象同時實現(xiàn)了Factory這里是通過繼承的方式來代理的,所以他即可以代理類也可以代理接口因為是繼承了被代理類,所以在java中子類是無法重寫父類final方法的,這也就解釋了為什么CGLIB無法代理final修飾的方法了
2.2.2 stataic 靜態(tài)代碼塊

結(jié)論: 這里面創(chuàng)建了一些后續(xù)要試用的變量引用
2.2.3 重寫父類方法

結(jié)論: 重寫的方法被final,防止后面被修改這里的var10000就是我們在創(chuàng)建代理時傳入的CglibProxy這里也就解釋了CGLIB是如何動態(tài)增強(qiáng)方法的基本邏輯(在每次調(diào)用方法時都會先去調(diào)用MethodInterceptor的實現(xiàn)類中的intercept方法,然后我們只需要在intercept方法中實現(xiàn)要加強(qiáng)的代碼即可)
2.3 代理方法調(diào)用過程分析
調(diào)用代理方法

結(jié)論: 創(chuàng)建代理對象fly通過調(diào)用代理對象fly.doFly()方法

3. 調(diào)用MethodInterceptor的intercept方法,這里就是調(diào)用我們的CglibProxy

4. 調(diào)用methodProxy.invokeSuper(o, params);這里就是要調(diào)用被代理類的原始方法

通過init()來初始化生成代理類和被代理類的FastClass

helper:

生成的FastClass文件

生成的FastClass文件的invoke方法

init完成后這里會繼續(xù)調(diào)用fci.f2.invoke(fci.i2, obj, args); 這里的fci.f2就是剛剛生成的代理對象FastCalss對象

這里程序會傳入17,調(diào)用代理類的CGLIB$doFly$0()方法;(大家可以debug看,每次生成的文件位置會不一樣)

調(diào)用代理類的CGLIB$doFly$0() 到這里基本可以知道它是如何幫助我們調(diào)用被代理類的方法了這里的super指的就是MyFly,因為CGLIB生成的代理類繼承了我們要被代理的類

到此這篇關(guān)于Java的CGLIB動態(tài)代理深入解析的文章就介紹到這了,更多相關(guān)CGLIB動態(tài)代理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot3各種配置的優(yōu)先級對比小結(jié)
SpringBoot3提供了多種配置來源以滿足不同場景下的需求,本文詳細(xì)介紹了SpringBoot3中的配置優(yōu)先級對比小結(jié),具有一定的參考價值,感興趣的可以了解一下2024-12-12
springboot CompletableFuture異步線程池詳解
這篇文章主要介紹了springboot CompletableFuture異步線程池的使用,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-04-04
mybatis類型轉(zhuǎn)換器如何實現(xiàn)數(shù)據(jù)加解密
這篇文章主要介紹了mybatis類型轉(zhuǎn)換器如何實現(xiàn)數(shù)據(jù)加解密,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09

