分析cglib動態代理的實現

前言

在上一篇專欄中,分析了JDK動態代理的實現,而這一篇就是分析cglib動態代理的實現,建議先看上一篇專欄再看這一篇,由於二者之間都是大同小異的,可是JDK動態代理會更加好理解一點,換言之,也就是cglib比較難,不過理解了JDK動態代理再來看cglib的動態代理就會如魚得水。java

基本原理

cglib是經過生成一個被代理類的子類來實現動態代理的。也就是生成的動態代理類會繼承被代理類。後面反編譯動態代理類時就會清楚了。數組

你能學到什麼

  1. cglib爲何能夠基於類來實現動態代理,與JDK動態代理的本質區別是什麼?
  2. cglib是如何調用被代理類的方法?
  3. cglib如何輸出代理類到本地?
  4. cglib使用methodProxy.invoke()爲何會棧溢出?
  5. cglib建立代理類的步驟(不包括ASM部分)?
  6. cglib是如何執行代理方法的?與JDK動態代理執行代理方法有什麼區別?

使用

同上一篇同樣,咱們經過一個例子進行講解,爲了便於理解,例子也繼續使用上一篇中的例子。緩存

步驟一

建立一個須要被代理的類,由於cglib能夠基於類進行代理(也能夠基於接口代理),因此咱們不須要建立一個接口,直接建立一個類便可。mybatis

public class Hello {
    public void sayHello(){
        System.out.println("say hello");
    }
}
複製代碼

步驟二

建立一個代理類,這個代理類須要實現一個MethodInterceptor接口,與JDK動態代理的InvocationHandler接口相似。函數

public class HelloInterceptor implements MethodInterceptor {
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before say hello");
        // 1. 這裏不能使用methodProxy.invoke(),會棧溢出,後面會有解釋
        // 2. 使用method.invoke()的時候不能使用參數中的o做爲執行對象,不然也會發生
        // 相似的棧溢出錯誤,必須自行另外建立一個新的對象,後面也會有解釋
        methodProxy.invokeSuper(o, objects);
        System.out.println("after say hello");
        return null;
    }
}
複製代碼

步驟三

public class Test {
    public static void main(String[] args) {
    
        // 不使用緩存,使用緩存的話,複雜度會比較高,咱們只看如何生成代理類
        System.setProperty("cglib.useCache", "false");
        
        // 建立一個加強器
        Enhancer enhancer = new Enhancer();
        
        // 設置須要代理的類,等同於JDK中newProxyInstance的第二個參數
        enhancer.setSuperclass(Hello.class);
        
        // 設置代理類,等同於JDK中newProxyInstance的第三個參數
        enhancer.setCallback(new HelloInterceptor());

        // 建立動態代理類
        Hello jack = (Hello) enhancer.create();
        
        // 調用方法
        jack.sayHello();
    }
}
複製代碼

執行結果

結果

源碼分析

分析源碼的時候首先不考慮緩存的問題,由於考慮緩存的話,複雜度基本上都在緩存那裏,有點脫離主題了,後面我會再分析帶有緩存的源碼。源碼分析

enhancer.create()

該方法會建立一個代理class,而且返回一個該class的實例對象,也就是會返回一個動態代理類的實例對象,會使用被代理類(Hello.class)的無參構造post

public Object create() {
    // 用於判斷是否須要建立對象,false表示須要建立對象
    classOnly = false;
    // 由於使用的是無參構造,因此該屬性爲null
    argumentTypes = null;
    // 建立動態代理class的方法
    return createHelper();
}
複製代碼

若是被代理類是一個有參構造的類,那麼可使用重載的create(Class[] argumentTypes, Object[] arguments),與上一個方法相似,只是多了參數類型測試

// 接收兩個參數
// 1. 參數類型數組
// 2. 具體的參數數組
public Object create(Class[] argumentTypes, Object[] arguments) {
    classOnly = false;
    if (argumentTypes == null || arguments == null || argumentTypes.length != arguments.length) {
        throw new IllegalArgumentException("Arguments must be non-null and of equal length");
    }
    this.argumentTypes = argumentTypes;
    this.arguments = arguments;
    return createHelper();
}
複製代碼

createHelper()

建立一個要生成的動態代理類的惟一鍵,用這個鍵來表示須要生成的動態代理類的惟一標識,而後將建立的工做委託給父類進行。this

private Object createHelper() {
    // 檢查設置的CallBack的類型是否符合要求
    preValidate();
    // 建立惟一標識
    Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
            ReflectUtils.getNames(interfaces),
            filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
            callbackTypes,
            useFactory,
            interceptDuringConstruction,
            serialVersionUID);
    this.currentKey = key;
    // 委託父類執行建立工做
    Object result = super.create(key);
    return result;
}
複製代碼

super.create()

調用了抽象的類生成器AbstractClassGenerator中的該方法。(若是)該方法將會嘗試從緩存中spa

protected Object create(Object key) {
    try {
        // 獲取ClassLoader,通常是AppClassLoader
        ClassLoader loader = getClassLoader();
        // classloader做爲鍵,緩存的是經過該classloader加載的動態代理類
        Map<ClassLoader, ClassLoaderData> cache = CACHE;
        ClassLoaderData data = cache.get(loader);
        if (data == null) {
            synchronized (AbstractClassGenerator.class) {
                cache = CACHE;
                data = cache.get(loader);
                if (data == null) {
                    Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
                    data = new ClassLoaderData(loader);
                    newCache.put(loader, data);
                    CACHE = newCache;
                }
            }
        }
        this.key = key;
        
        // 主要看這一句,這是建立而且獲取動態代理類的地方,由於咱們不使用緩存
        // 因此將會使用ASM直接建立一個動態代理類,而且使用ClassLoader 進行加載
        // 因此這裏返回的是一個Class對象。
        Object obj = data.get(this, getUseCache());
        
        // 若是返回的是Class對象,則建立一個該Class類的實例
        if (obj instanceof Class) {
            return firstInstance((Class) obj);
        }
        
        // (在開啓緩存的狀況下才會執行到這裏)若是返回的是一個
        // EnhancerFactoryData對象,那麼說明已經存在一個相應的動態代理Class對象
        return nextInstance(obj);
    } catch (RuntimeException e) {
        throw e;
    } catch (Error e) {
        throw e;
    } catch (Exception e) {
        throw new CodeGenerationException(e);
    }
}
複製代碼

data.get()

從緩存中獲取,由於咱們沒有開啓緩存,因此將會直接建立一個動態代理類

public Object get(AbstractClassGenerator gen, boolean useCache) {
    // 這裏useCache爲false,因此直接經過抽象類生成器建立
    if (!useCache) {
      // 執行這一句。
      // 傳遞了一個參數:ClassLoaderData.this,
      // 這個參數是表示執行這段代碼的ClassLoaderData對象,也就是標題的data對象
      // 實際上直接寫this也是同樣,由於這個方法是屬於ClassLoaderData這個內部類
      return gen.generate(ClassLoaderData.this);
    } else {
      Object cachedValue = generatedClasses.get(gen);
      return gen.unwrapCachedValue(cachedValue);
    }
}
複製代碼

gen.generate()

使用抽象的類生成器生成一個動態代理類,並使用類加載器加載

protected Class generate(ClassLoaderData data) {
    Class gen;
    Object save = CURRENT.get();
    CURRENT.set(this);
    try {
        // 獲取類加載,用於加載生成的動態代理類
        ClassLoader classLoader = data.getClassLoader();
        if (classLoader == null) {
            throw new IllegalStateException("ClassLoader is null while trying to define class " +
                    getClassName() + ". It seems that the loader has been expired from a weak reference somehow. " +
                    "Please file an issue at cglib's issue tracker.");
        }
        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
            }
        }
        // 使用ASM生成動態代理類的class文件
        // 咱們對具體是如何使用ASM生成class文件的過程不作分析
        // 由於這須要對JVM結構和class文件結構很是熟悉才能理解
        // 也不建議你們直接使用ASM(除非對class文件結構很是熟悉)。
        byte[] b = strategy.generate(this);
        
        // 獲取生成的動態代理類的類名,應該與上面的name是同樣的
        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 {
                // 經過classloader加載類文件,返回一個Class對象
                gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain);
            }
        }
        // 返回生成的Class對象
        return gen;
    } catch (RuntimeException e) {
        throw e;
    } catch (Error e) {
        throw e;
    } catch (Exception e) {
        throw new CodeGenerationException(e);
    } finally {
        CURRENT.set(save);
    }
}
複製代碼

而後將一直返回到super.create()方法,獲得一個動態代理類的Class對象。

由於返回的是一個Class對象,因此將會執行firstInstance()方法,該方法實際就是經過Class對象獲取到構造函數,經過構造函數建立一個實例出來,而後將實例返回。由於較簡單,就不貼代碼了。

分析動態代理類實現

輸出動態代理類

只須要在測試類的最前面加上一個系統屬性便可

public static void main(String[] args) {
    // 輸出生成的動態代理類
    // 第二參數:輸出的路徑
    System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "H:\\mybatis_demo");
    
    // 取消使用緩存,默認爲true
    System.setProperty("cglib.useCache", "false");

    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(Hello.class);
    enhancer.setCallback(new HelloInterceptor());
    
    Hello jack = (Hello) enhancer.create();
    jack.sayHello();
}
複製代碼

分析

public class Hello$$EnhancerByCGLIB$$35d006ca extends Hello implements Factory {
    private boolean CGLIB$BOUND;
    public static Object CGLIB$FACTORY_DATA;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static Object CGLIB$CALLBACK_FILTER;
    private static final Method CGLIB$sayHello$0$Method;
    private static final MethodProxy CGLIB$sayHello$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$equals$1$Method;
    private static final MethodProxy CGLIB$equals$1$Proxy;
    private static final Method CGLIB$toString$2$Method;
    private static final MethodProxy CGLIB$toString$2$Proxy;
    private static final Method CGLIB$hashCode$3$Method;
    private static final MethodProxy CGLIB$hashCode$3$Proxy;
    private static final Method CGLIB$clone$4$Method;
    private static final MethodProxy CGLIB$clone$4$Proxy;

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("com.lhd.cglib.Hello$$EnhancerByCGLIB$$35d006ca");
        Class var1;
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$equals$1$Method = var10000[0];
        CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
        CGLIB$toString$2$Method = var10000[1];
        CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
        CGLIB$hashCode$3$Method = var10000[2];
        CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
        CGLIB$clone$4$Method = var10000[3];
        CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
        CGLIB$sayHello$0$Method = ReflectUtils.findMethods(new String[]{"sayHello", "()V"}, (var1 = Class.forName("com.lhd.cglib.Hello")).getDeclaredMethods())[0];
        CGLIB$sayHello$0$Proxy = MethodProxy.create(var1, var0, "()V", "sayHello", "CGLIB$sayHello$0");
    }

    final void CGLIB$sayHello$0() {
        super.sayHello();
    }

    public final void sayHello() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            var10000.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
        } else {
            super.sayHello();
        }
    }

    final boolean CGLIB$equals$1(Object var1) {
        return super.equals(var1);
    }

    public final boolean equals(Object var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
            return var2 == null ? false : (Boolean)var2;
        } else {
            return super.equals(var1);
        }
    }

    final String CGLIB$toString$2() {
        return super.toString();
    }

    public final String toString() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
    }

    final int CGLIB$hashCode$3() {
        return super.hashCode();
    }

    public final int hashCode() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
            return var1 == null ? 0 : ((Number)var1).intValue();
        } else {
            return super.hashCode();
        }
    }

    final Object CGLIB$clone$4() throws CloneNotSupportedException {
        return super.clone();
    }

    protected final Object clone() throws CloneNotSupportedException {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
    }

    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) {
                return CGLIB$clone$4$Proxy;
            }
            break;
        case 1535311470:
            if (var10000.equals("sayHello()V")) {
                return CGLIB$sayHello$0$Proxy;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return CGLIB$equals$1$Proxy;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return CGLIB$toString$2$Proxy;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return CGLIB$hashCode$3$Proxy;
            }
        }

        return null;
    }

    public Hello$$EnhancerByCGLIB$$35d006ca() {
        CGLIB$BIND_CALLBACKS(this);
    }

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
        CGLIB$THREAD_CALLBACKS.set(var0);
    }

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
        CGLIB$STATIC_CALLBACKS = var0;
    }

    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        Hello$$EnhancerByCGLIB$$35d006ca var1 = (Hello$$EnhancerByCGLIB$$35d006ca)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }

            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }

    public Object newInstance(Callback[] var1) {
        CGLIB$SET_THREAD_CALLBACKS(var1);
        Hello$$EnhancerByCGLIB$$35d006ca var10000 = new Hello$$EnhancerByCGLIB$$35d006ca();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Callback var1) {
        CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
        Hello$$EnhancerByCGLIB$$35d006ca var10000 = new Hello$$EnhancerByCGLIB$$35d006ca();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        Hello$$EnhancerByCGLIB$$35d006ca var10000 = new Hello$$EnhancerByCGLIB$$35d006ca;
        switch(var1.length) {
        case 0:
            var10000.<init>();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        default:
            throw new IllegalArgumentException("Constructor not found");
        }
    }

    public Callback getCallback(int var1) {
        CGLIB$BIND_CALLBACKS(this);
        MethodInterceptor var10000;
        switch(var1) {
        case 0:
            var10000 = this.CGLIB$CALLBACK_0;
            break;
        default:
            var10000 = null;
        }

        return var10000;
    }

    public void setCallback(int var1, Callback var2) {
        switch(var1) {
        case 0:
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
        default:
        }
    }

    public Callback[] getCallbacks() {
        CGLIB$BIND_CALLBACKS(this);
        return new Callback[]{this.CGLIB$CALLBACK_0};
    }

    public void setCallbacks(Callback[] var1) {
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
    }

    static {
        CGLIB$STATICHOOK1();
    }
}
複製代碼

經過輸出的代理類咱們能夠看到咱們輸出的動態代理類其實是繼承於被代理類的,而且重寫了被代理類中的方法,由於是使用了繼承,final類是沒法被代理的,非final類的final方法也是沒法被重寫的

動態生成的代理類其實是被代理類的一個子類。cglib不但重寫了父類的方法,同時也重寫了Object類中的toString(),hashCode(),equals(),clone(),沒有重寫wait(),notify()等方法是由於他們是final方法,沒法重寫。

如何執行代理方法

當咱們拿到生成的代理類對象的時候,執行sayHello()方法時,實際執行的是下面的代碼

public final void sayHello() {
    MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
    if (var10000 == null) {
        CGLIB$BIND_CALLBACKS(this);
        var10000 = this.CGLIB$CALLBACK_0;
    }

    if (var10000 != null) {
        var10000.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
    } else {
        super.sayHello();
    }
}
複製代碼

MethodInterceptor類型的變量(例子中就是HelloInterceptor類)不爲空時,將會執行該類中的intercept()方法

咱們分析一下這個方法的參數:

  1. this: 也就是動態代理類的對象
  2. CGLIB$sayHello$0$Method:它是類型爲Method的靜態屬性,,在CGLIB$STATICHOOK1()方法中賦值,而該方法在最下面的靜態代碼塊中被調用。被賦值爲Hello類裏面的sayHello方法
  3. CGLIB$emptyArgs:傳遞參數,這個表示沒有參數,有參數的話也只是直接傳遞參數數組,很簡單
  4. CGLIB$sayHello$0$Proxy:是cglib本身爲這個方法建立的一個代理對象,內部是經過FastClass來執行原始方法的,它比經過反射來執行要快一些(之前),不過目前JDK版本的迭代,經過反射執行效率反而更加高。

棧溢出問題

當咱們調用methodProxy.invoke(o, objects)方法時,就會發生棧溢出。咱們看一下這個方法的內部是如何實現的

該方法接收兩個參數:

  1. 執行方法的對象
  2. 方法的參數
public Object invoke(Object obj, Object[] args) throws Throwable {
    try {
        // 會建立一個Hello類的FastClass類,該類用於較快調用指定的方法
        // 主要是經過index下標來肯定須要執行的方法。有興趣能夠自行反編譯查看
        init();
        FastClassInfo fci = fastClassInfo;
        // 1
        return fci.f1.invoke(fci.i1, obj, args);
    } catch (InvocationTargetException e) {
        throw e.getTargetException();
    } catch (IllegalArgumentException e) {
        if (fastClassInfo.i1 < 0)
            throw new IllegalArgumentException("Protected method: " + sig1);
        throw e;
    }
}
複製代碼

1中的那行代碼,就是真正執行方法的語句,咱們能夠debug看內部的屬性是什麼

經過debug咱們能夠看到 f1是一個 Hello$$FastClassByCGLIB$$7572df32類的對象,咱們能夠在生成的動態代理類下面找到這個類,咱們打開這個類,並找到它的 invoke方法

咱們執行這個方法傳遞的參數,能夠看到i1是0,黃色框部分。

咱們傳遞三個參數分別是:

  1. 0
  2. 動態代理類的對象
  3. 執行方法所須要的參數
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
    Hello var10000 = (Hello)var2;
    int var10001 = var1;

    try {
        switch(var10001) {
        case 0:
            var10000.sayHello();
            return null;
        case 1:
            return new Boolean(var10000.equals(var3[0]));
        case 2:
            return var10000.toString();
        case 3:
            return new Integer(var10000.hashCode());
        }
    } catch (Throwable var4) {
        throw new InvocationTargetException(var4);
    }

    throw new IllegalArgumentException("Cannot find matching method/constructor");
}
複製代碼

咱們經過這個源碼能夠看出實際上執行的是var10000.sayHello(),而var10000是咱們傳遞進來的動態代理對象,也就等於又執行了一次jack.sayHello();,而jack.sayHello()又會執行var10000.sayHello(),因此一直互相調用,直到發生棧溢出。

不發生棧溢出的方法

咱們分析完上一個會發生棧溢出的方法調用後,咱們來分析一下不會發生棧溢出的方法調用的原理。

當咱們調用的時methodProxy.invokeSuper(o, objects);時,就不會發生棧溢出的問題,咱們看一下這個方法的源碼

public Object invokeSuper(Object obj, Object[] args) throws Throwable {
    try {
        init();
        FastClassInfo fci = fastClassInfo;
        // 只有這一句不同
        return fci.f2.invoke(fci.i2, obj, args);
    } catch (InvocationTargetException e) {
        throw e.getTargetException();
    }
}
複製代碼

經過debug,咱們能夠看到 f2Hello$$EnhancerByCGLIB$$35d006ca$$FastClassByCGLIB$$518e6b66_3,它是爲生成的動態代理類生成的FastClass類。

咱們執行invoke方法傳遞的參數分別是:

  1. 17
  2. 動態代理類的對象
  3. 執行方法所須要的參數
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
    35d006ca var10000 = (35d006ca)var2;
    int var10001 = var1;

    try {
        switch(var10001) {
        case 0:
            return new Boolean(var10000.equals(var3[0]));
        case 1:
            return var10000.toString();
        case 2:
            return new Integer(var10000.hashCode());
        case 3:
            return var10000.clone();
        case 4:
            return var10000.newInstance((Callback[])var3[0]);
        case 5:
            return var10000.newInstance((Callback)var3[0]);
        case 6:
            return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
        case 7:
            var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
            return null;
        case 8:
            var10000.sayHello();
            return null;
        case 9:
            35d006ca.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
            return null;
        case 10:
            35d006ca.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
            return null;
        case 11:
            var10000.setCallbacks((Callback[])var3[0]);
            return null;
        case 12:
            return var10000.getCallbacks();
        case 13:
            return var10000.getCallback(((Number)var3[0]).intValue());
        case 14:
            return var10000.CGLIB$toString$2();
        case 15:
            return new Integer(var10000.CGLIB$hashCode$3());
        case 16:
            return var10000.CGLIB$clone$4();
        case 17:
            var10000.CGLIB$sayHello$0();
            return null;
        case 18:
            return new Boolean(var10000.CGLIB$equals$1(var3[0]));
        case 19:
            return 35d006ca.CGLIB$findMethodProxy((Signature)var3[0]);
        case 20:
            35d006ca.CGLIB$STATICHOOK1();
            return null;
        }
    } catch (Throwable var4) {
        throw new InvocationTargetException(var4);
    }

    throw new IllegalArgumentException("Cannot find matching method/constructor");
}
複製代碼

咱們能夠看到17是var10000.CGLIB$sayHello$0();,var10000就是咱們傳遞進來的動態代理類對象,也就是執行了動態代理類對象的CGLIB$sayHello$0()方法,咱們能夠看一下這個方法的源碼

final void CGLIB$sayHello$0() {
    super.sayHello();
}
複製代碼

實際上就是直接調用父類的sayHello方法,也就是最原始的那個方法。因此這裏並不會出現互相調用的局面。

還剩下一個method.invoke(o, objects)方法沒有講解。你們能夠本身去debug一下看看會不會報錯,原理跟methodProxy.invoke()相似。

總結

cglib動態代理和JDK動態代理本質的區別就是:

  • cglib對於類的代理是基於繼承的。cglib經過繼承來實現動態代理(也能夠經過接口)
  • JDK只能基於接口,由於它自身須要繼承Proxy類,而java不支持多繼承。而JDK只能經過實現接口來實現動態代理。

cglib動態代理的過程當中會生成三個Class文件(實際是五個,另外兩個不須要理解),分別是:

  1. 原始類的動態代理類
  2. 原始類的FastClass類
  3. 動態代理類的FastClass類

cglib調用原始方法是經過FastClass的下標進行調用的。而JDK動態代理是經過反射進行調用的。

尾聲

至此,cglib動態代理就講完了,固然,ASM操做字節碼生成動態代理文件部分由於不熟悉因此沒有去講解。可是不影響理解cglib動態代理的原理。寫了兩天,一共花了12個小時,加上debug,找資料,閱讀源碼,終於完成了。但願你們看到錯誤的地方多多包涵,我會虛心請教。

這幾天會總結出cglib動態代理和JDK動態代理的區別!

相關文章
相關標籤/搜索