CGLIB动态代理底层实现原理

一、前言

最近在探究Spring AOP的性能,发现最后是绕不开JDK动态代理和CGLIB动态代理这两个点。笔者心里大致有这么个概念:对于动态代理来说,CGLIB性能要好于JDK。也知道CGLIB是利用ASM技术基于继承子类实现动态代理,JDK是基于实现接口实现动态代理,但是对于底层实现还是比较模糊。今天就彻底整明白CGLIB动态代理的底层实现。

二、前置准备

(一)测试代码

CGLIB核心的几个概念:

  • 被代理对象,本案例【Dog】
  • 方法拦截器MethodInterceptor,本案例【CglibMethodInterceptor】
  • Enhance代理对象生成工具,本案例【TestMain测试主类中创建】

1. 自定义方法拦截器CglibMethodInterceptor

后面也会将MethodInterceptor说成Callback,其实是一个东西,MethodInterceptor是实现了Callback接口的。

typescript 复制代码
/**
 * 方法拦截器,不用依赖被代理业务类的引用
 */
public class CglibMethodInterceptor implements MethodInterceptor {

    /**
     * 功能主要是在调用业务类方法之前 之后添加统计时间的方法逻辑.
     * intercept 因为具有 MethodProxy methodProxy 参数的原因,不再需要代理类的引用对象了,直接通过 methodProxy 对象访问被代理对象的方法(这种方式更快)。
     * 当然 也可以通过反射机制,通过 method 引用实例    Object result = method.invoke(target, args); 形式反射调用被代理类方法,
     * target 实例代表被代理类对象引用, 初始化 CglibMethodInterceptor 时候被赋值 。但是Cglib不推荐使用这种方式
     *
     * @param object      代表Cglib 生成的动态代理类 对象本身
     * @param method      代理类中被拦截的接口方法 Method 实例
     * @param args        接口方法参数
     * @param methodProxy 用于调用父类真正的业务类方法。可以直接调用被代理类接口方法
     * @return 被代理类方法执行返回值
     * @throws Throwable
     */
    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("before");
        MonitorUtil.start();
        Object result = methodProxy.invokeSuper(object, args);
//        Object result = methodProxy.invoke(object, args);
        System.out.println("after");
        MonitorUtil.finish(method.getName());
        return result;
    }
}

2. 被代理类

csharp 复制代码
public class Dog {

    public String call() {
        System.out.println("wang wang wang");
        return "Dog ..";
    }
 }

3. 切面方法

csharp 复制代码
/**
 * 方法用时监控类,作为一个切面 ,具有两个方法
 */
public class MonitorUtil {

    private static final ThreadLocal<Long> tl = new ThreadLocal<>();

    public static void start() {
        tl.set(System.currentTimeMillis());
    }

    /**
     * 结束时打印耗时
     * @param methodName 监控方法名
     */
    public static void finish(String methodName) {
        long finishTime = System.currentTimeMillis();
        System.out.println(methodName + "方法执行耗时" + (finishTime - tl.get()) + "ms");
    }
}

4. 测试主类

java 复制代码
public class TestMain {

    /**
     * 用于生成 Cglib 动态代理类工具方法
     * @param target 代表需要 被代理的 委托类的 Class 对象
     * @return 代理类对象
     */
    public static Object cglibProxyGenerator(Class target) {
        // 创建加强器,用来创建动态代理类
        Enhancer enhancer = new Enhancer();
        // 为代理类指定需要代理的类,也即是父类
        enhancer.setSuperclass(target);
        // 设置方法拦截器回调引用,对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept() 方法进行拦截
        enhancer.setCallback(new CglibMethodInterceptor());
        // 创建cglib 代理类
        return enhancer.create();
    }

    public static void main(String[] args) throws ClassNotFoundException {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "classFiles");
        Dog poolDog = (Dog) cglibProxyGenerator(Dog.class);
        poolDog.call();

    }
}

(二)CGLIB生成的子类

Dog$$EnhancerByCGLIB$$beb9d601

java 复制代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.allen.testDynamicProxy.cglibProxy;

import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

// 实现net.sf.cglib.proxy.Factory的目的是提供一些创建代理对象实例的工厂方法,这些方法会比反射创建对象快【clazz.newInstance()】
public class Dog$$EnhancerByCGLIB$$beb9d601 extends Dog 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;
    // Dog类call的Method对象
    private static final Method CGLIB$call$0$Method;
    // Dog类call方法的代理对象
    private static final MethodProxy CGLIB$call$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    // Object类equals方法的Method对象
    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;

    /**
     * CGLIB$call$0$Method和CGLIB$call$0$Proxy就是MethodInterceptor接口的入参
     * MethodProxy 比 Method反射调用方法更快
     */
    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        // 加载生成的增强类
        Class var0 = Class.forName("com.allen.testDynamicProxy.cglibProxy.Dog$$EnhancerByCGLIB$$beb9d601");
        Class var1;
        // 通过反射获取Object类的Method对象
        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];
        // 为 Method 创建对应的 MethodProxy 对象
        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");
        // Dog类call方法Method对象
        CGLIB$call$0$Method = ReflectUtils.findMethods(new String[]{"call", "()Ljava/lang/String;"}, (var1 = Class.forName("com.allen.testDynamicProxy.cglibProxy.Dog")).getDeclaredMethods())[0];
        CGLIB$call$0$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "call", "CGLIB$call$0");
    }

    final String CGLIB$call$0() {
        return super.call();
    }
    // 重写 Dog类的call方法,添加CallBack回调【即执行MethodInterceptor的intercept方法,即我们自定义的CglibMethodInterceptor的intercept方法】
    public final String call() {
        // 这边获取MethodInterceptor为null
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            // 重新绑定MethodInterceptor
            CGLIB$BIND_CALLBACKS(this);
            // 这边还是null
            var10000 = this.CGLIB$CALLBACK_0;
        }

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

    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 371634473:
            if (var10000.equals("call()Ljava/lang/String;")) {
                return CGLIB$call$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;
    }

    // 实例化构造方法会绑定CallBacks
    public Dog$$EnhancerByCGLIB$$beb9d601() {
        CGLIB$BIND_CALLBACKS(this);
    }

    // 设置CallBack到ThreadLocal
    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;
    }
    /**
     * 判断并绑定CallBack对象【就是MethodInterceptor对象,也即自定义的CglibMethodInterceptor】
     */
    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        Dog$$EnhancerByCGLIB$$beb9d601 var1 = (Dog$$EnhancerByCGLIB$$beb9d601)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];
        }

    }
    /**
     * 使用无参构造方法创建增强后的子类新实例
     * @param callbacks 多个MethodInterceptor对象数组
     * @return new instance of the same type
     */ 
    public Object newInstance(Callback[] var1) {
        CGLIB$SET_THREAD_CALLBACKS(var1);
        Dog$$EnhancerByCGLIB$$beb9d601 var10000 = new Dog$$EnhancerByCGLIB$$beb9d601();
        // 将ThreadLocal的 CallBacks 至空
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }
    /**
     * 使用无参构造方法创建增强后的子类新实例
     * 该对象只能指定一个Callback【MethodInterceptor】
     * @param callback 自定义的MethodInterceptor对象
     * @return new instance of the same type
     */
    public Object newInstance(Callback var1) {
        CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
        Dog$$EnhancerByCGLIB$$beb9d601 var10000 = new Dog$$EnhancerByCGLIB$$beb9d601();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }
    /** 本案例中,实例化增强子类的时候就是调用此方法
     * @param types 构造方法参数类型
     * @param args 构造方法参数
     * @param callbacks 多个CallBack对象数组
     * @return new instance of the same type
     */
    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        Dog$$EnhancerByCGLIB$$beb9d601 var10000 = new Dog$$EnhancerByCGLIB$$beb9d601;
        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();
    }
}

(三)CGLIB生成的FastClass-1【简称f1】

Dog$$FastClassByCGLIB$$7ac19ed7

java 复制代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.allen.testDynamicProxy.cglibProxy;

import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.reflect.FastClass;

public class Dog$$FastClassByCGLIB$$7ac19ed7 extends FastClass {
    public Dog$$FastClassByCGLIB$$7ac19ed7(Class var1) {
        super(var1);
    }

    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case 371634473:
            if (var10000.equals("call()Ljava/lang/String;")) {
                return 0;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return 1;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return 2;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return 3;
            }
        }

        return -1;
    }

    public int getIndex(String var1, Class[] var2) {
        switch(var1.hashCode()) {
        case -1776922004:
            if (var1.equals("toString")) {
                switch(var2.length) {
                case 0:
                    return 2;
                }
            }
            break;
        case -1295482945:
            if (var1.equals("equals")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("java.lang.Object")) {
                        return 1;
                    }
                }
            }
            break;
        case 3045982:
            if (var1.equals("call")) {
                switch(var2.length) {
                case 0:
                    return 0;
                }
            }
            break;
        case 147696667:
            if (var1.equals("hashCode")) {
                switch(var2.length) {
                case 0:
                    return 3;
                }
            }
        }

        return -1;
    }

    public int getIndex(Class[] var1) {
        switch(var1.length) {
        case 0:
            return 0;
        default:
            return -1;
        }
    }

    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        Dog var10000 = (Dog)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
            case 0:
                return var10000.call();
            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");
    }

    public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
        Dog var10000 = new Dog;
        Dog var10001 = var10000;
        int var10002 = var1;

        try {
            switch(var10002) {
            case 0:
                var10001.<init>();
                return var10000;
            }
        } catch (Throwable var3) {
            throw new InvocationTargetException(var3);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public int getMaxIndex() {
        return 3;
    }
}

(四)CGLIB生成的FastClass-2【简称f2】

Dog$$EnhancerByCGLIB$$beb9d601$$FastClassByCGLIB$$916924fc

java 复制代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.allen.testDynamicProxy.cglibProxy;

import com.allen.testDynamicProxy.cglibProxy.Dog..EnhancerByCGLIB..beb9d601;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.reflect.FastClass;

public class Dog$$EnhancerByCGLIB$$beb9d601$$FastClassByCGLIB$$916924fc extends FastClass {
    public Dog$$EnhancerByCGLIB$$beb9d601$$FastClassByCGLIB$$916924fc(Class var1) {
        super(var1);
    }

    public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch(var10000.hashCode()) {
        case -2055565910:
            if (var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
                return 1;
            }
            break;
        case -1882565338:
            if (var10000.equals("CGLIB$equals$1(Ljava/lang/Object;)Z")) {
                return 4;
            }
            break;
        case -1457535688:
            if (var10000.equals("CGLIB$STATICHOOK1()V")) {
                return 8;
            }
            break;
        case -1411842725:
            if (var10000.equals("CGLIB$hashCode$3()I")) {
                return 6;
            }
            break;
        case -1212270792:
            if (var10000.equals("CGLIB$call$0()Ljava/lang/String;")) {
                return 5;
            }
            break;
        case -894172689:
            if (var10000.equals("newInstance(Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                return 20;
            }
            break;
        case -623122092:
            if (var10000.equals("CGLIB$findMethodProxy(Lnet/sf/cglib/core/Signature;)Lnet/sf/cglib/proxy/MethodProxy;")) {
                return 13;
            }
            break;
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) {
                return 17;
            }
            break;
        case -419626537:
            if (var10000.equals("setCallbacks([Lnet/sf/cglib/proxy/Callback;)V")) {
                return 9;
            }
            break;
        case 371634473:
            if (var10000.equals("call()Ljava/lang/String;")) {
                return 2;
            }
            break;
        case 560567118:
            if (var10000.equals("setCallback(ILnet/sf/cglib/proxy/Callback;)V")) {
                return 12;
            }
            break;
        case 811063227:
            if (var10000.equals("newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                return 19;
            }
            break;
        case 973717575:
            if (var10000.equals("getCallbacks()[Lnet/sf/cglib/proxy/Callback;")) {
                return 11;
            }
            break;
        case 1221173700:
            if (var10000.equals("newInstance([Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
                return 18;
            }
            break;
        case 1230699260:
            if (var10000.equals("getCallback(I)Lnet/sf/cglib/proxy/Callback;")) {
                return 10;
            }
            break;
        case 1306468936:
            if (var10000.equals("CGLIB$toString$2()Ljava/lang/String;")) {
                return 3;
            }
            break;
        case 1584330438:
            if (var10000.equals("CGLIB$SET_STATIC_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
                return 0;
            }
            break;
        case 1800494055:
            if (var10000.equals("CGLIB$clone$4()Ljava/lang/Object;")) {
                return 7;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return 14;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return 15;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return 16;
            }
        }

        return -1;
    }

    public int getIndex(String var1, Class[] var2) {
        switch(var1.hashCode()) {
        case -1776922004:
            if (var1.equals("toString")) {
                switch(var2.length) {
                case 0:
                    return 15;
                }
            }
            break;
        case -1295482945:
            if (var1.equals("equals")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("java.lang.Object")) {
                        return 14;
                    }
                }
            }
            break;
        case -1053468136:
            if (var1.equals("getCallbacks")) {
                switch(var2.length) {
                case 0:
                    return 11;
                }
            }
            break;
        case -124978609:
            if (var1.equals("CGLIB$equals$1")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("java.lang.Object")) {
                        return 4;
                    }
                }
            }
            break;
        case -60403779:
            if (var1.equals("CGLIB$SET_STATIC_CALLBACKS")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                        return 0;
                    }
                }
            }
            break;
        case -29025555:
            if (var1.equals("CGLIB$hashCode$3")) {
                switch(var2.length) {
                case 0:
                    return 6;
                }
            }
            break;
        case 3045982:
            if (var1.equals("call")) {
                switch(var2.length) {
                case 0:
                    return 2;
                }
            }
            break;
        case 52714989:
            if (var1.equals("CGLIB$call$0")) {
                switch(var2.length) {
                case 0:
                    return 5;
                }
            }
            break;
        case 85179481:
            if (var1.equals("CGLIB$SET_THREAD_CALLBACKS")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                        return 1;
                    }
                }
            }
            break;
        case 94756189:
            if (var1.equals("clone")) {
                switch(var2.length) {
                case 0:
                    return 17;
                }
            }
            break;
        case 147696667:
            if (var1.equals("hashCode")) {
                switch(var2.length) {
                case 0:
                    return 16;
                }
            }
            break;
        case 161998109:
            if (var1.equals("CGLIB$STATICHOOK1")) {
                switch(var2.length) {
                case 0:
                    return 8;
                }
            }
            break;
        case 495524492:
            if (var1.equals("setCallbacks")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                        return 9;
                    }
                }
            }
            break;
        case 1154623345:
            if (var1.equals("CGLIB$findMethodProxy")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("net.sf.cglib.core.Signature")) {
                        return 13;
                    }
                }
            }
            break;
        case 1543336189:
            if (var1.equals("CGLIB$toString$2")) {
                switch(var2.length) {
                case 0:
                    return 3;
                }
            }
            break;
        case 1811874389:
            if (var1.equals("newInstance")) {
                switch(var2.length) {
                case 1:
                    String var10001 = var2[0].getName();
                    switch(var10001.hashCode()) {
                    case -845341380:
                        if (var10001.equals("net.sf.cglib.proxy.Callback")) {
                            return 20;
                        }
                        break;
                    case 1730110032:
                        if (var10001.equals("[Lnet.sf.cglib.proxy.Callback;")) {
                            return 18;
                        }
                    }
                case 2:
                default:
                    break;
                case 3:
                    if (var2[0].getName().equals("[Ljava.lang.Class;") && var2[1].getName().equals("[Ljava.lang.Object;") && var2[2].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
                        return 19;
                    }
                }
            }
            break;
        case 1817099975:
            if (var1.equals("setCallback")) {
                switch(var2.length) {
                case 2:
                    if (var2[0].getName().equals("int") && var2[1].getName().equals("net.sf.cglib.proxy.Callback")) {
                        return 12;
                    }
                }
            }
            break;
        case 1905679803:
            if (var1.equals("getCallback")) {
                switch(var2.length) {
                case 1:
                    if (var2[0].getName().equals("int")) {
                        return 10;
                    }
                }
            }
            break;
        case 1951977610:
            if (var1.equals("CGLIB$clone$4")) {
                switch(var2.length) {
                case 0:
                    return 7;
                }
            }
        }

        return -1;
    }

    public int getIndex(Class[] var1) {
        switch(var1.length) {
        case 0:
            return 0;
        default:
            return -1;
        }
    }

    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        beb9d601 var10000 = (beb9d601)var2;
        int var10001 = var1;

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

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
        beb9d601 var10000 = new beb9d601;
        beb9d601 var10001 = var10000;
        int var10002 = var1;

        try {
            switch(var10002) {
            case 0:
                var10001.<init>();
                return var10000;
            }
        } catch (Throwable var3) {
            throw new InvocationTargetException(var3);
        }

        throw new IllegalArgumentException("Cannot find matching method/constructor");
    }

    public int getMaxIndex() {
        return 20;
    }
}

三、CGLIB代理类创建流程

代理类的创建主要是在enhancer.create()方法调用后进行的,大致流程如下:

(一)代理类的创建

首先看下在实例化代理类 期间绑定Callback的过程「即自定义的MethodInterceptor」,核心源码【net.sf.cglib.proxy.Enhancer.EnhancerFactoryData#newInstance】:

注意这边的setThreadCallbacks是个final类型的变量,会在EnhancerFactoryData的构造方法中赋值为代理类 Dog$$EnhancerByCGLIB$$beb9d601SET_THREAD_CALLBACKS方法对象,对应的SET_THREAD_CALLBACKS源码如下:

java 复制代码
	// 设置CallBack到ThreadLocal
    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
		// CGLIB$THREAD_CALLBACKS是个final static变量,在代理类的静态代码块中赋值为ThreadLocal()
		// 代理类的静态代码块下面会讲到
        CGLIB$THREAD_CALLBACKS.set(var0);
    }

代理类 Dog$$EnhancerByCGLIB$$beb9d601类加载的时候,会执行代理类的静态方法块,期间会给每个被代理类 Dog的成员方法创建一个MethdProxy代理方法对象。

(二)创建MethodProxy

MethodProxy封装了原始Dog类的方法签名【sig1】,对应代理类方法的签名【sig2】以及代理类的一些创建信息【原始类和代理类的名称、类生成策略等等】。对应的代理类的静态代码块内容如下:

java 复制代码
// CGLIB$call$0$Method和CGLIB$call$0$Proxy就是MethodInterceptor接口的入参
static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        // 加载生成的增强类
        Class var0 = Class.forName("com.allen.testDynamicProxy.cglibProxy.Dog$$EnhancerByCGLIB$$beb9d601");
        Class var1;
        // 通过反射获取Object类的Method对象
        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];
        // 为 Method 创建对应的 MethodProxy 对象
        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");
        // Dog类call方法Method对象
        CGLIB$call$0$Method = ReflectUtils.findMethods(new String[]{"call", "()Ljava/lang/String;"}, (var1 = Class.forName("com.allen.testDynamicProxy.cglibProxy.Dog")).getDeclaredMethods())[0];
        // var1: 被代理类  var0:代理类
        CGLIB$call$0$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "call", "CGLIB$call$0");
    }

对应MethodProxy.create()【net.sf.cglib.proxy.MethodProxy#creat()】方法:

java 复制代码
    /**
     * For internal use by {@link Enhancer} only; see the {@link net.sf.cglib.reflect.FastMethod} class
     * for similar functionality.
     * @param c1 被代理类
     * @param c2 代理类
     * @param desc 方法描述【"()Ljava/lang/String;"】
     * @param name1 方法1名称【"call"】
     * @param name2 方法2名称【"CGLIB$call$0"】
     */
    public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
        MethodProxy proxy = new MethodProxy();
		// 构建方法签名
        proxy.sig1 = new Signature(name1, desc);
        proxy.sig2 = new Signature(name2, desc);
        proxy.createInfo = new CreateInfo(c1, c2);
        return proxy;
    }

关于方法签名的debug信息【后面会用这个方法签名在Fastclass中查询对应的index索引】:

(三)创建CreateInfo

CreateInfoMethodProxy的一个内部类,主要保存代理类的一些创建信息。

java 复制代码
private static class CreateInfo
    {	
		// 对应Dog原始类
        Class c1;
		// 代理类Dog$$EnhancerByCGLIB$$beb9d601
        Class c2;
		// 代理类命名策略
        NamingPolicy namingPolicy;
		// 代理类生成策略
        GeneratorStrategy strategy;
        boolean attemptLoad;
        
        public CreateInfo(Class c1, Class c2)
        {
            this.c1 = c1;
            this.c2 = c2;
            AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
            if (fromEnhancer != null) {
                namingPolicy = fromEnhancer.getNamingPolicy();
                strategy = fromEnhancer.getStrategy();
                attemptLoad = fromEnhancer.getAttemptLoad();
            }
        }
    }

四、CGLIB动态代理调用流程

当执行目标方法时,代理对象调用流程如下:

相信看完上面的流程图,基本就对CGLIB的底层实现有了大致的概念。当然下面我还会进行详细分析。

(一)重写父类方法

基于一开始的demo,笔者从调用目标方法一步步分析。⚠️main方法调用poolDog.call();时,实际上执行的是代理对象的call()方法,代理对象 的生成已经在上一节分析过了。那我们直接看代理对象call()方法,源码如下:

java 复制代码
    /**
     * 重写 Dog类的call方法,添加CallBack回调
     * 【即执行MethodInterceptor的intercept方法,即我们自定义的  CglibMethodInterceptor的intercept方法】 
     */
	public final String call() {
        // 从成员属性CGLIB$CALLBACK_0获取MethodInterceptor
		// 第一次调用是null,进入下面的if逻辑
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
			// 重新绑定MethodInterceptor,并赋值给成员属性CGLIB$CALLBACK_0
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
		// @param this 代理对象本身
		// @param CGLIB$call$0$Method Dog类call方法Method对象【静态代码块已赋值】
		// @param CGLIB$emptyArgs Dog类call方法参数【我这边是void,所以没有】
		// @param CGLIB$call$0$Proxy Dog类call方法的代理方法对象【静态代码块已赋值】
        return var10000 != null ? (String)var10000.intercept(this, CGLIB$call$0$Method, CGLIB$emptyArgs, CGLIB$call$0$Proxy) : super.call();
    }

	/**
     * 判断并绑定CallBack对象【就是MethodInterceptor对象,也即自定义的CglibMethodInterceptor】
     */
    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
		// var0即代理类当前对象,将其对象的引用指向var1
        Dog$$EnhancerByCGLIB$$beb9d601 var1 = (Dog$$EnhancerByCGLIB$$beb9d601)var0;
		// 这边判断是true,创建代理类的时候通过反射已将对应的Callback设置到ThreadLocal
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
			// 将ThreadLocal中的Callback赋值给var10000
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }
			// 将Callback赋值给成员属性CGLIB$CALLBACK_0
            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }

当调用代理对象 重写过的call()方法时,会执行对应的方法拦截器,即我们自定义的MethodInterceptorintercept方法的逻辑【本案例中对应自定义拦截器类CglibMethodInterceptor】,对应intercept方法的传参和含义在上面的代码注释中已说明。

(二)原始父类方法的匹配调用

接下来,在MethodInterceptorintercept方法中调用的methodProxy.invokeSuper(object, args);时,最终就会执行父类Dogcall()方法。具体怎么调用执行的,先看MethodProxy.invokeSuper(object, args);的执行逻辑,源码如下:

java 复制代码
/**
     * 调用CGLIB增强的父类目标方法
     * @param obj the enhanced object, must be the object passed as the first
     * argument to the MethodInterceptor
     * @param args the arguments passed to the intercepted method; you may substitute a different
     * argument array as long as the types are compatible
     * @see MethodInterceptor#intercept
     * @throws Throwable the bare exceptions thrown by the called method are passed through
     * without wrapping in an <code>InvocationTargetException</code>
     */
    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();
        }
    }

1. init()方法

在上面的流程图中我们也大致能看到init()方法干了些什么事。主要是在处理FastClassFastClass是什么? 简单理解,FastClass代理对象 方法 到 被代理对象 方法的映射【对应FastClass的源码已在前置准备中贴出】。 ⚠️init()方法只会在第一次被调用的时候去执行FastClass创建等操作。

1)先看下init()方法源码:
java 复制代码
private void init()
    {
        /* 
         * Using a volatile invariant allows us to initialize the FastClass and
         * method index pairs atomically.
         * 
         * Double-checked locking is safe with volatile in Java 5.  Before 1.5 this 
         * code could allow fastClassInfo to be instantiated more than once, which
         * appears to be benign.
         */
        if (fastClassInfo == null)
        {
            synchronized (initLock)
            {
                if (fastClassInfo == null)
                {
					// 获取代理类的创建信息【上面有提过】
                    CreateInfo ci = createInfo;
					// 新建FastClassInfo对象
                    FastClassInfo fci = new FastClassInfo();
					// 生成FastClass f1,并赋值给FastClassInfo的成员属性
                    fci.f1 = helper(ci, ci.c1);
                    fci.f2 = helper(ci, ci.c2);
					// 根据方法签名,获取代理类中对应call方法在f1中的索引
                    fci.i1 = fci.f1.getIndex(sig1);
					// 根据方法签名,获取代理类中对应call方法在f2中的索引
                    fci.i2 = fci.f2.getIndex(sig2);
                    fastClassInfo = fci;
                    createInfo = null;
                }
            }
        }
    }

/* 
 * FastClassInfo也是MethodProxy的一个内部类
 */
private static class FastClassInfo
    {
		// 对应前置准备中的f1
        FastClass f1;
		// 对应前置准备中的f2
        FastClass f2;
        int i1;
        int i2;
    }

init()方法其实就是创建了两个FastClass,然后建立FastClass代理对象 关于 目标方法 的 索引

2)fci.f2.invoke(fci.i2, obj, args);

invoke的传参说明:

  • i2: 获取代理类中对应call方法在f2中的索引
  • obj: 代理对象本身
  • args: 目标方法的传参

f2中invoke部分源码:

接下就会调用代理对象对应的方法:

看到这是不是有点明了了,最后这不就是执行了我们父类Dogcall()方法吗。那整个核心的实现逻辑和调用流程大致就是这样的。

(三)CGLIB死循环了

上面一小节关于目标方法的调用是通过net.sf.cglib.proxy.MethodProxy#invokeSuper完成的,CGLIB中还有一个net.sf.cglib.proxy.MethodProxy#invoke。在自定义的MethodProxy中,将invokeSuper改成invoke,运行一下,报错了,无限递归导致栈溢出 。   在解释原因之前,有没有发现一个问题,前面不是生成了两个FastClass吗,截止现在我们只用到了一个。你的猜想正确,invoke方法就是用的f1中的索引。   死循环的问题我这边不详细解释,以一张图说明【其中的元素信息完全基于前置准备的代码,同学们可以自己本地写个demo尝试】:

五、性能:CGLIB vs JDK

其实说实话,工作中并没有说单单就因为将动态代理模式从JDK换成CGLIB,性能就有明显提升的情况,大部分情况性能相差不多。但是明显CGLIB适用性更广,SpringBoot将AOP的动态代理默认设置成了CGLIB,我想估计也不是性能使然。   理论上说,针对JDK动态代理的Method.invoke()和CGLIB的MethodProxy.invokeSuper()这两个invoke来说,CGLIB感觉更加优雅些,但是刚开始第一次调用CGLIB是比较慢的,还记得上面提到的init()吗。非要钻牛角尖说CGLIB性能更好的话,可能是MethodAccessor的锅。

Method.invoke(target,params),实际是MethodAccessor实例真正完成反射调用。Java 版本的 MethodAccessorImpl 调用效率比 Native 版本要快 20 倍以上,但是 Java 版本加载时要比 Native 多消耗 3-4 倍资源,所以默认会调用 Native 版本,如果调用次数超过 15 次以后,就会选择运行效率更高的 Java 版本。但是⚠️:存放method的reflectionDataSoftReference的,即在某些内存比较苛刻的情况下是可能被回收的【通过-XX:SoftRefLRUPolicyMSPerMB这个参数来控制回收的时机】。一旦回收,就需要调用getDeclaredMethods0 进行遍历查找,重新缓存。

关于JDK代理的细节,可以参考我之前的文章:www.heapdump.cn/article/275...

over,希望这篇吐血肝货,可以帮你理解CGLIB底层实现原理。继续肝💪·····


相关推荐
阿杆1 分钟前
垃圾回收不是回收站:JVM GC 背后的爱恨情仇
java·后端·面试
幻奏岚音29 分钟前
Java数据结构——第 2 章线性表学习笔记
java·数据结构·笔记·学习·算法·排序算法
惜鸟37 分钟前
springboot 项目的包结构设计(二)
java·spring boot
惜鸟39 分钟前
使用MyBatis Dynamic SQL处理复杂的JOIN或子查询
java·spring boot
你过来啊你1 小时前
单例模式详解(Java实现)
java
听忆.1 小时前
Java修改接口 校验一个或多个字段不可重复(自定义注解)
java·开发语言·数据库
桦说编程1 小时前
写时复制COW核心原理解读
java·性能优化·函数式编程
xcs194051 小时前
java 基础方法 list分页
java·开发语言
惜鸟1 小时前
Spring Boot中使用MyBatis Generator生成动态SQL
java·spring boot
天天摸鱼的java工程师1 小时前
如何实现一个线程安全的缓存组件?——八年Java开发的实战总结
java·后端·面试