• 欢迎访问 winrains 的个人网站!
  • 本网站主要从互联网整理和收集了与Java、网络安全、Linux等技术相关的文章,供学习和研究使用。如有侵权,请留言告知,谢谢!

分析cglib动态代理的实现

Java技术 winrains 来源:奋斗的小皇帝 7个月前 (04-23) 62次浏览

前言

在上一篇专栏中,分析了JDK动态代理的实现,而这一篇就是分析cglib动态代理的实现,建议先看上一篇专栏再看这一篇,因为两者之间都是大同小异的,但是JDK动态代理会更加好理解一点,换言之,也就是cglib比较难,不过理解了JDK动态代理再来看cglib的动态代理就会如鱼得水。

基本原理

cglib是通过生成一个被代理类的子类来实现动态代理的。也就是生成的动态代理类会继承被代理类。后面反编译动态代理类时就会清楚了。

你能学到什么

  1. cglib为什么可以基于类来实现动态代理,与JDK动态代理的本质区别是什么?
  2. cglib是如何调用被代理类的方法?
  3. cglib如何输出代理类到本地?
  4. cglib使用methodProxy.invoke()为什么会栈溢出?
  5. cglib创建代理类的步骤(不包括ASM部分)?
  6. cglib是如何执行代理方法的?与JDK动态代理执行代理方法有什么区别?

使用

同上一篇一样,我们通过一个例子进行讲解,为了便于理解,例子也继续使用上一篇中的例子。

步骤一

创建一个需要被代理的类,因为cglib可以基于类进行代理(也可以基于接口代理),所以我们不需要创建一个接口,直接创建一个类即可。

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)的无参构造

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()

创建一个要生成的动态代理类的唯一键,用这个键来表示需要生成的动态代理类的唯一标识,然后将创建的工作委托给父类进行。

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中的该方法。(如果)该方法将会尝试从缓存中

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,找资料,阅读源码,终于完成了。希望大家看到错误的地方多多包涵,我会虚心请教。

作者:奋斗的小皇帝

链接:https://juejin.im/post/5e32ea77e51d45307546b11a


版权声明:文末如注明作者和来源,则表示本文系转载,版权为原作者所有 | 本文如有侵权,请及时联系,承诺在收到消息后第一时间删除 | 如转载本文,请注明原文链接。
喜欢 (2)