1. 程式人生 > >Cglib動態代理實現解析

Cglib動態代理實現解析

JDK 動態代理原始碼解讀 已經知道了JDK 動態代理的實現邏輯,這裡我們來學習一下Cglib 的實現邏輯。以方便對動態代理有一個全面的認識。

首先,我們來看一下生成代理類的時序圖,對比起JDK的實現,它複雜了很多。

Cglib代理類時序圖

整體看上去比較難以理解,那我們來看下這些類圖,可能更加清晰些。

代理類生成類圖

來看看入口類 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類,同時,必須包含無參的構造方法。