Cglib動態代理實現解析
在 JDK 動態代理原始碼解讀 已經知道了JDK 動態代理的實現邏輯,這裡我們來學習一下Cglib 的實現邏輯。以方便對動態代理有一個全面的認識。
首先,我們來看一下生成代理類的時序圖,對比起JDK的實現,它複雜了很多。
整體看上去比較難以理解,那我們來看下這些類圖,可能更加清晰些。
來看看入口類 Enhancer
,它繼承自 AbstractClassGenerator
,而 AbstractClassGenerator
實現了 ClassGenerator
介面,ClassLoaderData
又是 AbstractClassGenerator
的內部類,哦,原來它們是一家的。既然知道了主體結構,那我們來看一下,核心的實現程式碼,整體邏輯與JDK基本一致生成類名,生成位元組碼物件,最後生成代理類例項。
protected Class generate(ClassLoaderData data) {
Class gen;
...
try {
ClassLoader classLoader = data.getClassLoader();
...
synchronized (classLoader) {
// 生成類名
String name = generateClassName(data.getUniqueNamePredicate());
data.reserveName(name);
this .setClassName(name);
}
if (attemptLoad) {
try {
gen = classLoader.loadClass(getClassName());
return gen;
} catch (ClassNotFoundException e) {
// ignore
}
}
// 生成代理類位元組碼
byte[] b = strategy.generate(this );
String className = ClassNameReader.getClassName(new ClassReader(b));
ProtectionDomain protectionDomain = getProtectionDomain();
// 生成代理類位元組碼物件
synchronized (classLoader) { // just in case
if (protectionDomain == null) {
gen = ReflectUtils.defineClass(className, b, classLoader);
} else {
gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain);
}
}
return gen;
} catch (RuntimeException e) {
...
}
}
在上面的程式碼中沒有生成例項物件的方法,它們是:
abstract protected Object firstInstance(Class type) throws Exception;
abstract protected Object nextInstance(Object instance) throws Exception;
具體的實現邏輯都在 Enhancer
裡面。
好吧,上面列舉了一堆,但還是沒有看到代理類的真容,下面,我們將生成好的代理類class檔案輸出,反編譯檢視更具體的實現。
在 DebuggingClassWriter
裡面有如下一段程式碼:
public static final String DEBUG_LOCATION_PROPERTY = "cglib.debugLocation";
static {
debugLocation = System.getProperty(DEBUG_LOCATION_PROPERTY);
if (debugLocation != null) {
System.err.println("CGLIB debugging enabled, writing to '" + debugLocation + "'");
try {
Class clazz = Class.forName("org.objectweb.asm.util.TraceClassVisitor");
traceCtor = clazz.getConstructor(new Class[]{ClassVisitor.class, PrintWriter.class});
} catch (Throwable ignore) {
}
}
}
DEBUG_LOCATION_PROPERTY
可通過執行時的環境變數配置,用於指定代理類class檔案的存放路徑。
public static void main(String[] args) {
String userDir = System.getProperty("user.dir");
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, userDir);
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SystemMgrImpl.class);
enhancer.setCallback(new SystemMgrTxnMethodInterceptor());
SystemMgrImpl proxyInstance = (SystemMgrImpl) enhancer.create();
System.out.println(proxyInstance.updateUser());
}
執行程式後,會在專案的根路徑下生成class檔案,如果不知道路徑,在控制中也會輸出具體的存放路徑。會生成三個類,其中類名不帶FastClass
的class檔案就是最終的代理類。
這裡,我們進行反編譯,得到如下原始碼:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.qchery.basics.design.pattern.proxy;
import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class SystemMgrImpl$$EnhancerByCGLIB$$3e3db737 extends SystemMgrImpl implements Factory {
...
private MethodInterceptor CGLIB$CALLBACK_0;
private static final Method CGLIB$updateUser$0$Method;
private static final MethodProxy CGLIB$updateUser$0$Proxy;
static {
// 獲取代理類Class位元組碼
Class var0 = Class.forName("com.qchery.basics.design.pattern.proxy.SystemMgrImpl$$EnhancerByCGLIB$$3e3db737");
// 獲取目標類Class位元組碼
Class var1 = Class.forName("com.qchery.basics.design.pattern.proxy.SystemMgrImpl");
Method[] var10000 = ReflectUtils.findMethods(new String[]{"updateUser"}, var1.getDeclaredMethods());
CGLIB$updateUser$0$Method = var10000[0];
// 為代理方法建立MethodProxy
CGLIB$updateUser$0$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "updateUser", "CGLIB$updateUser$0");
}
final String CGLIB$updateUser$0() {
return super.updateUser();
}
public final String updateUser() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
// 呼叫 MethodInterceptor
return var10000 != null ? (String)var10000.intercept(this, CGLIB$updateUser$0$Method, CGLIB$emptyArgs, CGLIB$updateUser$0$Proxy) : super.updateUser();
}
...
}
通過上面的程式碼,我們可以分析得出如下類圖:
其中,代理類繼承目標類,併為所有方法生成一個MethodProxy
用於代理目標方法,在呼叫代理類的方法時,會委託MethodInterceptor
呼叫intercept
方法。因此,在實現MethodInterceptor
時,需要通過 proxy.invokeSuper(obj, args)
呼叫目標類的實現,如果調成了代理類的實現會形成無限遞迴。
注:目標類不可是final類,同時,必須包含無參的構造方法。