https://javatar.iteye.com/blog/814426
參考Dubbo的選型實踐
- Jdk動態(tài)代理
使用Component.DynamicProxyPerformanceTest輸出動態(tài)代理class文件,使用javap -c觀察字節(jié)碼,使用jdGui或Luyten反編譯工具查看反編譯出的源碼(更清晰明了,無需去看字節(jié)碼)
//為什么動態(tài)代理只能代理接口?因為生成的代理類繼承了Proxy,無法再繼承其他類
public final class $proxy0 extends Proxy implements CountService
{
private static Method m1;
private static Method m3;
static {
try {
//通過反射獲取當(dāng)前接口以及Object對象的所有方法(含未列出的hashCode()等)
$proxy0.m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
$proxy0.m3 = Class.forName("aop.CountService").getMethod("count", (Class<?>[])new Class[0]);
}
}
public final boolean equals(final Object o) {
//super.h為父類Proxy.InvocationHandler字段
//調(diào)用其invoke方法
return (boolean)super.h.invoke(this, $proxy0.m1, new Object[] { o });
}
public final int count() {
return (int)super.h.invoke(this, $proxy0.m3, null);
}
}
所以說,jdk動態(tài)代理使用字節(jié)碼技術(shù)創(chuàng)建代理類,代理類中通過反射獲取原始方法method并調(diào)用自定義的InvocationHandler
- ASM
//通過classWriter寫字節(jié)碼然后轉(zhuǎn)換為字節(jié)數(shù)組
byte[] code = classWriter.toByteArray();
//通過Jdk.ClassLoader實例的方法根據(jù)字節(jié)碼數(shù)組創(chuàng)建class
ClassLoader.defineClass(name, code, 0, code.length);
asm pom依賴已經(jīng)改成了org.ow2.asm
- Cglib
cglib是在asm基礎(chǔ)上進行的封裝,pom包含了asm的依賴,所以測試asm無需單獨再依賴asm
//該設(shè)置用于輸出cglib動態(tài)代理產(chǎn)生的類
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");
選型分析
Jdk,Cglib,JavassistProxy創(chuàng)建出來的代理類包含equals()和hashCode()等Object對象原生方法,JavassistByte和ASM不含
測試發(fā)現(xiàn),直接調(diào)用CountService.count()的性能是使用反射調(diào)用method.invoke(CountServic)的2-4倍
Jdk,Cglib,JavassistProxy在回調(diào)函數(shù)中暴露Method,Jdk,JavassistProxy直接通過反射調(diào)用,Cglib通過MethodProxy調(diào)用
JavassistByte通過字符串形式的代碼創(chuàng)建class,ASM通過ClassWriter直接寫入字節(jié)碼創(chuàng)建class,創(chuàng)建后直接調(diào)用CountService.count(),不使用反射
測試結(jié)果:
NoProxy>ASM=JavassistByte>Cglib>Jdk>JavassistProxy,考慮使用方便,優(yōu)先使用JavassistByte
ASM和JavassistByte大約比無Proxy調(diào)用慢10%左右,是后面3者的2~3倍,直覺認(rèn)為主要差別在于字節(jié)碼class函數(shù)直接調(diào)用和后面3者method反射調(diào)用
- SpringAop
根據(jù)Spring的官方文檔,性能不是選擇使用Jdk或Cglib的重要因素