CGLIB动态代理源码分析


CGLIB是一个开源项目,可以在运行期间扩展Java类,实现Java接口等待。底层是字节码处理框架ASM,来转换字节码和生成新的类。

理论上也可直接ASM来生成代码,但是操作比较复杂。

CGLIB动态代理使用

先导入依赖:

<dependencies>
    <dependency>
        <groupId>org.sonatype.sisu.inject</groupId>
        <artifactId>cglib</artifactId>
        <version>3.1.1</version>
    </dependency>
</dependencies>

被代理的类:

public class Target {
    public void f() {
        System.out.println("Target f()");
    }
    public void g() {
        System.out.println("Target g()");
    }
}

拦截器:

public class Interceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理前---------");
        // 为啥要invokeSuper
        Object result = methodProxy.invokeSuper(o,objects);
        System.out.println("代理后---------");
        return result;
    }
}

这里有个invokeSuper,为什么不用invoke呢?分析代理类时说。

测试类:

public class Test {
    public static void main(String[] args) {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,
                "./");
        //实例化一个增强器,cglib的一个class generator
        Enhancer enhancer = new Enhancer();
        //设置目标类
        enhancer.setSuperclass(Target.class);
        //设置拦截对象
        //可以设置多个,不是一个方法可以被拦截多次
        //而是目标类中不同的方法可以被不同的拦截器拦截
        enhancer.setCallback(new Interceptor());
        //生成代理类,返回实例
        Target target = (Target) enhancer.create();
        target.f();
        target.g();

        //结果:
        //CGLIB debugging enabled, writing to './'
        //代理前---------
        //Target f()
        //代理后---------
        //代理前---------
        //Target g()
        //代理后---------
    }
}

使用步骤

  • 创建Enhancer实例
  • setSuperClass方法设置目标类
  • setCallback方法设置拦截对象
  • create生成代理类

CGLIB动态代理源码解析

代理类分析

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package cn.orzlinux.cglibTest;

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;

public class Target$$EnhancerByCGLIB$$557584f8 extends Target implements Factory {
    private boolean CGLIB$BOUND;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static final Method CGLIB$g$0$Method;
    private static final MethodProxy CGLIB$g$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$f$1$Method;
    private static final MethodProxy CGLIB$f$1$Proxy;
    //...

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("cn.orzlinux.cglibTest.Target$$EnhancerByCGLIB$$557584f8");
        Class var1;
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$finalize$2$Method = var10000[0];
        CGLIB$finalize$2$Proxy = MethodProxy.create(var1, var0, "()V", "finalize", "CGLIB$finalize$2");
        CGLIB$equals$3$Method = var10000[1];
        CGLIB$equals$3$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$3");
        CGLIB$toString$4$Method = var10000[2];
        CGLIB$toString$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$4");
        CGLIB$hashCode$5$Method = var10000[3];
        CGLIB$hashCode$5$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$5");
        CGLIB$clone$6$Method = var10000[4];
        CGLIB$clone$6$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$6");
        var10000 = ReflectUtils.findMethods(new String[]{"g", "()V", "f", "()V"}, (var1 = Class.forName("cn.orzlinux.cglibTest.Target")).getDeclaredMethods());
        //被代理类方法对象
        CGLIB$g$0$Method = var10000[0];
        //初始化代理类方法对象
        CGLIB$g$0$Proxy = MethodProxy.create(var1, var0, "()V", "g", "CGLIB$g$0");
        CGLIB$f$1$Method = var10000[1];
        CGLIB$f$1$Proxy = MethodProxy.create(var1, var0, "()V", "f", "CGLIB$f$1");
    }

    // 目标类的g方法
    final void CGLIB$g$0() {
        super.g();
    }

    public final void g() {
        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$g$0$Method, CGLIB$emptyArgs, CGLIB$g$0$Proxy);
        } else {
            super.g();
        }
    }
    //。。。finalize toString...方法省略
}

代理类继承了目标类Target:

public class Target$$EnhancerByCGLIB$$557584f8 extends Target implements Factory

对于Target中的非private方法,代理类生成两个方法:

//被代理类的g方法
final void CGLIB$g$0() {
    super.g();
}

//代理类的g()方法,override
public final void g() {
    //获取拦截对象
    MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
    if (var10000 == null) {
        CGLIB$BIND_CALLBACKS(this);
        var10000 = this.CGLIB$CALLBACK_0;
    }

    if (var10000 != null) {
        //拦截器对象的intecept方法
        var10000.intercept(this, CGLIB$g$0$Method, CGLIB$emptyArgs, CGLIB$g$0$Proxy);
    } else {
        super.g();
    }
}

拦截器对象何时获得?

 private static final void CGLIB$BIND_CALLBACKS(Object var0) {
     Target$$EnhancerByCGLIB$$557584f8 var1 = (Target$$EnhancerByCGLIB$$557584f8)var0;
     if (!var1.CGLIB$BOUND) {
         var1.CGLIB$BOUND = true;
         //ThreadLocal里获取,何时赋值?
         //都是在newInstance里设置的,因为代理类实现了Factory接口
         //Factory接口有newInstance方法,所以并不是这里设置的,要看Enhancer
         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];
     }

 }

Enhancer

public class Enhancer extends AbstractClassGenerator
{
    //...
    public Object create() {
        classOnly = false;
        argumentTypes = null;
        return createHelper();
    }
    
    private Object createHelper() {
        validate();
        if (superclass != null) {
            setNamePrefix(superclass.getName());
        } else if (interfaces != null) {
            setNamePrefix(interfaces[ReflectUtils.findPackageProtected(interfaces)].getName());
        }
        // KEY_FACTORY.newInstance生成一个代理对象,保存了用户设置的代理信息
        // create创建代理对象
        return super.create(KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
                                                    ReflectUtils.getNames(interfaces),
                                                    filter,
                                                    callbackTypes,
                                                    useFactory,
                                                    interceptDuringConstruction,
                                                    serialVersionUID));
    }
}

create跳转几次到达:

 private Object createUsingReflection(Class type) {
     setThreadCallbacks(type, callbacks);
     try{
         if (argumentTypes != null) {
             return ReflectUtils.newInstance(type, argumentTypes, arguments);
         } else {
             return ReflectUtils.newInstance(type);
         }
     }finally{
         // clear thread callbacks to allow them to be gc'd
         setThreadCallbacks(type, null);
     }
 }

发现设置了callback。

MethodProxy

对照拦截器代码:

public class Interceptor implements MethodInterceptor {
    @Override
    //o: 被代理对象
    //method:要调用的方法
    //objects: 方法参数
    //methodProxy 方法代理, 源自:
    //CGLIB$g$0$Proxy = MethodProxy.create(var1, var0, "()V", "g", "CGLIB$g$0");
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理前---------");
        // 为啥要invokeSuper
        Object result = methodProxy.invokeSuper(o,objects);
        System.out.println("代理后---------");
        return result;
    }
}

invoke()和invokeSuper()

为什么有MethodProxy?代理的是被代理对象的方法和代理对象的方法。

invokeg()也就是代理类的方法。

invokeSuper: CGLIB$g$0也就是被代理类的方法。

public class Interceptor implements MethodInterceptor {
    private final Target target = new Target();
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理前---------");
        // 为啥要invokeSuper
        //Object result = methodProxy.invokeSuper(o,objects);

        //1.ok
        //methodProxy.invokeSuper(target,objects);

        //2. error
        //methodProxy.invokeSuper(target,objects); //error
        // > Target cannot be cast to Target$$EnhancerByCGLIB$$55...

        //3. error
        //methodProxy.invoke(o,objects);
        // 栈溢出,一直循环调用

        methodProxy.invokeSuper(o,objects);
        System.out.println("代理后---------");
        return null;
    }
}

MethodProxy对象创建

CGLIB$f$1$Proxy = MethodProxy.create(var1, var0, "()V", "f", "CGLIB$f$1");

()V是void的意思,返回参数,最后两个参数是函数的两个名字,代表调用代理类函数和被代理类函数。

源码:

// c1是被代理类class
// c2是代理类class
// desc被代理方法返回值类型
// name1 被代理方法名,如test
// name2代理类中的CGLIB$test$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); //被代理方法签名:void test()
    // Signature:
    //public class Signature {
    //    private String name;
    //    private String desc;
    //     // ...
    //}
    proxy.sig2 = new Signature(name2, desc);
    proxy.createInfo = new CreateInfo(c1, c2); //存放被代理类和代理类信息
    return proxy;
}

创建好MethodProxy对象之后,就可以在g()方法里面调用了:

//拦截器对象的intecept方法
var10000.intercept(this, CGLIB$g$0$Method, CGLIB$emptyArgs, CGLIB$g$0$Proxy);

而在自定义拦截其中,用invokeSuper进行被代理类的调用。

public class Interceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理前---------");
        methodProxy.invokeSuper(o,objects);
        System.out.println("代理后---------");
        return null;
    }
}

invokeSuper

public Object invoke(Object obj, Object[] args) throws Throwable {
    try {
        init();
        FastClassInfo fci = fastClassInfo;
        return fci.f1.invoke(fci.i1, obj, args);
    } catch (InvocationTargetException e) {
        //...
    }
}

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) {
        //...
    }
}

这里代码比较相似,不同的就是f1,f2,i1,i2。这个是因为代理方法里面是对应的两个方法。

private void init()
{
    //双重校验单例模式
    if (fastClassInfo == null)
    {
        synchronized (initLock)
        {
            if (fastClassInfo == null)
            {
                CreateInfo ci = createInfo;

                FastClassInfo fci = new FastClassInfo();
                //被代理类的FastClass代理类
                fci.f1 = helper(ci, ci.c1);
                //代理类的FastClass代理类
                fci.f2 = helper(ci, ci.c2);
                
                //预先生成方法对应的下表,调用时利用下标
                //找到方法,性能高
                fci.i1 = fci.f1.getIndex(sig1);
                fci.i2 = fci.f2.getIndex(sig2);
                fastClassInfo = fci;
                createInfo = null;
            }
        }
    }
}

生成的class有三个文件:

image-20220128214540657

FastClass的invoke

public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        //var1000是调用方法对应的类,没有用反射,而是直接调用
        //所以会稍快一些
        Target var10000 = (Target)var2;
        int var10001 = var1;

        try {
            switch(var10001) {
            case 0:
                var10000.g();
                return null;
            case 1:
                var10000.f();
                return null;
            case 2:
                var10000.wait();
                return null;
            case 3:
                ...
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

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

CGLIB和JDK动态代理区别

Spring 中的动态代理,如果代理对象有接口,就用 JDK 动态代理,否则就是 Cglib 动态代理。

区别

  • jdk动态代理:是根据接口生成代理类,这个继承Proxy类,在这个代理类的构造函数里把handler给代理类,代理类在调用方法的时候,用的是handler,handler手里又有一个原对象实例,调用的时候用反射进行调用。
  • cglib动态代理:利用ASM框架,来生成目标对象的子类,在这个代理类的方法里调用拦截器,拦截器传入的是方法代理,而不是方法,运行的时候也不是用反射,而是直接调用的对象。

一个刁钻的问题:为什么还要用JDK动态代理?

在调用次数少的时候jdk好像相对效率高些。

参考链接

设计模式【3.3】-- CGLIB动态代理源码解读

JDK Proxy 和 CGLib 有什么区别?

cglib源码分析(四):cglib 动态代理原理分析