分析cglib动态代理的实现(上)

简介: 分析cglib动态代理的实现(上)

前言

在上一篇专栏中,分析了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();
    }
}

执行结果

image.png

源码分析

分析源码的时候首先不考虑缓存的问题,因为考虑缓存的话,复杂度基本上都在缓存那里,有点脱离主题了,后面我会再分析带有缓存的源码。

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方法,无法重写。

目录
相关文章
|
11月前
|
缓存 Java 数据库连接
分析JDK动态代理的实现
分析JDK动态代理的实现
68 0
|
Java Maven
JDK动态代理和CGLIB动态代理的区别及实例
JDK动态代理和CGLIB动态代理的区别及实例
202 0
|
11月前
|
Java
分析cglib动态代理的实现(下)
分析cglib动态代理的实现(下)
49 0
|
Java 索引 Spring
静态代理?动态代理?JDK动态代理和CGLIB包实现动态代理的区别
什么是静态代理?什么是动态代理?JDK动态代理和CGLIB包实现动态代理的区别
118 1
静态代理?动态代理?JDK动态代理和CGLIB包实现动态代理的区别
|
Java 测试技术 Spring
动态代理:Cglib原理讲解
动态代理:Cglib原理讲解
144 1
|
Java Spring
jdk动态代理和cglib动态代理
只有聪明人才能看见的简介~( ̄▽ ̄~)~
87 0
jdk动态代理和cglib动态代理
|
设计模式 Java 索引
jdk动态代理和cglib动态代理的原理分析(上)
jdk动态代理和cglib动态代理的原理分析(上)
jdk动态代理和cglib动态代理的原理分析(上)
|
Java 索引
jdk动态代理和cglib动态代理的原理分析(下)
jdk动态代理和cglib动态代理的原理分析(下)
223 0
jdk动态代理和cglib动态代理的原理分析(下)
|
设计模式 Java
【动态代理】—— JDK和cglib的动态代理
【动态代理】—— JDK和cglib的动态代理
142 0
【动态代理】—— JDK和cglib的动态代理
|
设计模式 Java API
静态代理、动态代理(JDK动态代理,Cglib动态代理)(1)
静态代理、动态代理(JDK动态代理,Cglib动态代理)(1)
129 0
静态代理、动态代理(JDK动态代理,Cglib动态代理)(1)