CGLIB源码易懂解析

Posted Fire king

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CGLIB源码易懂解析相关的知识,希望对你有一定的参考价值。

CGLIB源码易懂解析

1.测试代码

public class InfoDemo 
    public void welcome (String person)
        System.out.println("welcome :" + person);
    

public class CglibInfoProxy implements MethodInterceptor 
    private Object target;

    public Object newInstance(Object source) 
        target = source;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable 
        System.out.println("before method!!!");
        //生成的代理类字节码中调用
        Object value = methodProxy.invokeSuper(o, objects);
        //Object value = methodProxy.invoke(o, objects);
        return value;
    

    public static void main(String[] args) 
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\\\development\\\\classes");
        InfoDemo instance = (InfoDemo) new CglibInfoProxy().newInstance(new InfoDemo());
        instance.welcome("zhangsan");
    

2.运行后生成的三个字节码文件

代理类:InfoDemo$$EnhancerByCGLIB$$45152a9a.class
代理类的FastClass:

InfoDemo$$EnhancerByCGLIB$$45152a9a$$FastClassByCGLIB$$778b2fd5.class

被代理类的FastClass:InfoDemo$$FastClassByCGLIB$$6332e5ad.class

3.源码追溯

①主方法生成代理对象的demo块运行后出现了三个字节码文件,如2所示

InfoDemo instance = (InfoDemo) new CglibInfoProxy().newInstance(new InfoDemo());

newInstance方法的细节:

public Object newInstance(Object source) 
        target = source;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    

InfoDemo$$EnhancerByCGLIB$$45152a9a.class有一块静态代码块会初始化一些数据,如下:

    static 
        CGLIB$STATICHOOK1();
    

    static void CGLIB$STATICHOOK1() 
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("test.InfoDemo$$EnhancerByCGLIB$$45152a9a");
        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$welcome$0$Method = ReflectUtils.findMethods(new String[]"welcome", "(Ljava/lang/String;)V", (var1 = Class.forName("test.InfoDemo")).getDeclaredMethods())[0];
        CGLIB$welcome$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)V", "welcome", "CGLIB$welcome$0");
    

这里只要记住一点var1赋值过两次,都是在ReflectUtils中findMethods方法赋值的:

1.Object类
2.被代理类InfoDemo

var0是代理类
MethodProxy.create参数格式:

var1,var0,方法描述符,var1的方法,var0的方法

instance.welcome("zhangsan");JVM会调用代理类字节码文件InfoDemo$$EnhancerByCGLIB$$45152a9a.classwelcome方法,如下:

    public final void welcome(String var1) 
        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$welcome$0$Method, new Object[]var1, CGLIB$welcome$0$Proxy);
         else 
            super.welcome(var1);
        
    

疑云:
1.CGLIB$CALLBACK_0从哪来
2.CGLIB$BIND_CALLBACKS做了什么
3.intercept方法又是什么
解答:
1.CGLIB$CALLBACK_0有可能一开始就应该为空,又或者在到这步之前赋过值,但是细看如下代码,既让对var10000进行判空,那么有极大甚至说90%可能到这步理应为空,所以说我们暂时先走 CGLIB$BIND_CALLBACKS(this);的逻辑。

if (var10000 == null) 
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        

CGLIB$BIND_CALLBACKS(this);

    private static final void CGLIB$BIND_CALLBACKS(Object var0) 
        InfoDemo$$EnhancerByCGLIB$$45152a9a var1 = (InfoDemo$$EnhancerByCGLIB$$45152a9a)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];
        

    

疑云:
1.CGLIB$BOUND的true or false
2.有CGLIB$THREAD_CALLBACKS.get();应该在之前哪里调用代理类的set方法set过
3.CGLIB$STATIC_CALLBACKS又是哪里来的
解答:
1.对于整块代码,核心都是当GLIB$BOUND=false才执行,姑且认为是false
2.CGLIB$THREAD_CALLBACKS.get();在生成代理类的enhancer.create()中set过,因此,转到⑤看下具体逻辑验证。
3.CGLIB$STATIC_CALLBACKSzaEnhancer类中有生成过方法签名,也许在enhancer.create()的时候执行过。
enhancer.create()
一路追到protected Object create(Object key)方法,

return obj instanceof Class ? this.firstInstance((Class)obj) : this.nextInstance(obj);

先看firstInstance,再追到

private static void setThreadCallbacks(Class type, Callback[] callbacks) 
        setCallbacksHelper(type, callbacks, "CGLIB$SET_THREAD_CALLBACKS");
    

深度调用:可以看出执行了名为“CGLIB$SET_THREAD_CALLBACKS”的方法

private static void setCallbacksHelper(Class type, Callback[] callbacks, String methodName) 
        try 
            Method setter = getCallbacksSetter(type, methodName);
            setter.invoke((Object)null, callbacks);
         catch (NoSuchMethodException var4) 
            throw new IllegalArgumentException(type + " is not an enhanced class");
         catch (IllegalAccessException var5) 
            throw new CodeGenerationException(var5);
         catch (InvocationTargetException var6) 
            throw new CodeGenerationException(var6);
        
    

我们去搜一下代理类的“CGLIB$SET_THREAD_CALLBACKS”方法,果然

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

最后我们再回到④
由于var10000不再是空了,所以直接走下面的逻辑

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

这段代码的释义:
var10000引用赋值给Callback[],Callback[]的第一个槽位就是var10000所指对象,再强转成MethodInterceptor引用赋值给CGLIB$CALLBACK_0。因此③中 var10000 = this.CGLIB\\$CALLBACK_0;,var10000就有值了,而且最后的值是代理类(var10000多次变幻)。
⑥接③var10000.intercept(this, CGLIB$welcome$0$Method, new Object[]var1, CGLIB$welcome$0$Proxy);
我们说过var10000最终是代理类,所以会执行代理类的intercept方法,如下:
先输出,再调methodProxy.invokeSuper(o, objects);

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable 
        System.out.println("before method!!!");
        Object value = methodProxy.invokeSuper(o, objects);
        return value;
    

methodProxy.invokeSuper(o, objects);
MethodProxy.FastClassInfo fci = this.fastClassInfo;可以看出是FastClass,再由fci.f2.invoke(fci.i2, obj, args);可知是代理类的FastClass调用invoke方法(fci.f2是代理类的FastClass,那么fci.f1是被代理类的FastClass)

    public Object invokeSuper(Object obj, Object[] args) throws Throwable 
        try 
            this.init();
            MethodProxy.FastClassInfo fci = this.fastClassInfo;
            return fci.f2.invoke(fci.i2, obj, args);
         catch (InvocationTargetException var4) 
            throw var4.getTargetException();
        
    

疑惑:
1.fci.i2的值从哪里来
解答:
this.init();

    private void init() 
        if (this.fastClassInfo == null) 
            synchronized(this.initLock) 
                if (this.fastClassInfo == null) 
                    MethodProxy.CreateInfo ci = this.createInfo;
                    MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();
                    fci.f1 = helper(ci, ci.c1);
                    fci.f2 = helper(ci, ci.c2);
                    fci.i1 = fci.f1.getIndex(this.sig1);
                    fci.i2 = fci.f2.getIndex(this.sig2);
                    this.fastClassInfo = fci;
                    this.createInfo = null;
                
            
        

    

我们不难发现fci.f1和fci.f2分别是被代理类FastClass和代理类的FastClass,因此这两个方法需分别到对应的class文件去看实现。

fci.i1 = fci.f1.getIndex(this.sig1);
fci.i2 = fci.f2.getIndex(this.sig2);

我们看代理类的FastClass的getIndex方法:
不难看出,是通过散列值去返回一些整型值赋值给fci.i2。我们重点关注与被代理类方法调用的返回值,例如8,因此,我们明确了fci.i2=8

 public int getIndex(Signature var1) 
        String var10000 = var1.toString();
        switch(var10000.hashCode()) 
        case -1882565338:
            if (var10000.equals("CGLIB$equals$1(Ljava/lang/Object;)Z")) 
                return 17;
            
            break;
        case -1870561232:
            if (var10000.equals("CGLIB$findMethodProxy(Lorg/springframework/cglib/core/Signature;)Lorg/springframework/cglib/proxy/MethodProxy;")) 
                return 9;
            
            break;
        case -1745842178:
            if (var10000.equals("setCallbacks([Lorg/springframework/cglib/proxy/Callback;)V")) 
                return 10;
            
            break;
        case -1641413109:
            if (var10000.equals("newInstance([Lorg/springframework/cglib/proxy/Callback;)Ljava/lang/Object;")) 
                return 5;
            
            break;
        case -1457535688:
            if (var10000.equals("CGLIB$STATICHOOK1()V")) 
                return 15;
            
            break;
        case -1411842725:
            if (var10000.equals("CGLIB$hashCode$3()I")) 
                return 19;
            
            break;
        case -1034266769:
            if (var10000.equals("CGLIB$SET_STATIC_CALLBACKS([Lorg/springframework/cglib/proxy/Callback;)V")) 
                return 11;
            
            break;
        case -1025895669:
            if (var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lorg/springframework/cglib/proxy/Callback;)V")) 
                return 12;
            
            break;
        case -988317324:
            if (var10000.equals("newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lorg/springframework/cglib/proxy/Callback;)Ljava/lang/Object;")) 
                return 6;
            
            break;
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) 
                return 3;
            
            break;
        case 233072605:
            if (var10000.equals("welcome(Ljava/lang/String;)V")) 
                return 8;
            
            break;
        case 610042816:
            if (var10000.equals("newInstance(Lorg/springframework/cglib/proxy/Callback;)Ljava/lang/Object;")) 
                return 4;
            
            break;
        case 1013143764:
            if (var10000.equals("CGLIB$welcome$0(Ljava/lang/String;)V")) 
                return 16;
            
            break;
        case 1132856532:
            if (var10000.equals("getCallbacks()[Lorg/springframework/cglib/proxy/Callback;")) 
                return 14;
            
            break;
        case 1246779367:
            if (var10000.equals("setCallback(ILorg/springframework/cglib/proxy/Callback;)V")) 
                return 7;
            
            break;
        case 1306468936:
            if (var10000.equals("CGLIB$toString$2()Ljava/lang/String;")) 
                return 18;
            
            break;
        case 1364367423:
            if (var10000.equals("getCallback(I)Lorg/springframework/cglib/proxy/Callback;")) 
                return 13;
            
            break;
        case 1800494055:
            if (var10000.equals("CGLIB$clone$4()Ljava/lang/Object;")) 
                return 20Java动态代理——JDK和CGlib(简单易懂)

Spring源码深度解析-《源码构建》

JDK和cglib动态代理原理

追踪解析 jdk Proxy 源码

cglib测试例子和源码详解

cglib源码学习交流