CGLIB个人理解

。在看过大量关于CGLIB的文章后,我总结了一下自己的理解。

首先先给出几个本文的几个对象
下面展示一些 代码片段

被代理对象

public class Student {
    public void test1(int i){
        System.out.println(i);
    }
}

自己定义拦截的方法

public class ProxyForStudent implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Before");
        method.invoke(new Student(),1);
//        methodProxy.invokeSuper(o,objects);
        System.out.println("After");
        return null;
    }
}

测试类

public class test {
    public static void main(String[] args) throws Exception {
    System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "你想放的地方");
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(Student.class);
    enhancer.setCallback(new ProxyForStudent());
    Student student = (Student) enhancer.create();
    student.test1(1);
    }
}

接下来展示关于上方生成的student的子类(也就是代理对象的源码)接下来我将这个类称为“小A”

/*只展示“小A”的重要的目标*/
public class Student$$EnhancerByCGLIB$$807c5493 extends Student implements Factory {
	private MethodInterceptor CGLIB$CALLBACK_0;
	private static final Method CGLIB$test1$0$Method;
	private static final MethodProxy CGLIB$test1$0$Proxy;
	 final void CGLIB$test1$0(int var1) {
        super.test1(var1);
    }

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

正如你所见到的,在测试类中使用的任何方法都是“小A”中的方法。接下来我来解释下所谓的重要的部分。

下方的“小A”的成员变量就是上方代码片段中的的 ProxyForStudent

private MethodInterceptor CGLIB$CALLBACK_0;

下方的Method对象就是 Student对象(被代理对象)中的Method对象,即是test1()

private static final Method CGLIB$test1$0$Method;

下方的MethodProxy 对象 是CGLIB 生成的 方法代理 (重点!!!)

private static final MethodProxy CGLIB$test1$0$Proxy;

介绍完所谓的几个重要部分后。

我们接下来讲一下执行流程和一些容易错误的点(关于为什么invoke会死循环)

首先,CGLIB会生成3个class文件

代理对象(小A) : Student$$EnhancerByCGLIB$$807c5493
代理对象的FastClass: Student$$EnhancerByCGLIB$$807c5493$$FastClassByCGLIB$$22cae79c
被代理对象的FastClass: Student$$FastClassByCGLIB$$22cae79c

Q:什么是FastClass,为什么可以加快执行效率
FastClass是CGLIB生成一个类,该类中通过swtich和对应传进来值执行对应的方法。
为什么这样做呢,为了解决反射的性能问题
是不是感觉解释的很模糊。接下来会讲解怎么执行的。

简单解释完FastClas后就是关于执行流程了

1.执行小A的test1

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

如果写了代理方法,则进入代理方法(不考虑没写的情况)。

   @Override
   public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
       System.out.println("Before");
       method.invoke(new Student(),1);
//        methodProxy.invokeSuper(o,objects);
       System.out.println("After");
       return null;
   }

进入代理方法后会有一行 MethodProxy 的 invokeSuper(这里其实可以用invoke代替,但是参数不一样,不然会出现死循环)
invokeSuper()代码展示:

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

首先会执行init() 。简单说下init的作用:init()是给MethodProxy所代理的方法 和 fastclass进行初始化

init()

  private void init() {
        if (this.fastClassInfo == null) {
            synchronized(this.initLock) {
                if (this.fastClassInfo == null) {
                    CreateInfo ci = this.createInfo;
                    FastClassInfo fci = new 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;
                }
            }
        }

createInfo记录了 c1 c2这两个fastclass,c1就是小A的fastclass ,c2就是被代理类的fastclass

FastClassInfo中记录4个重要的变量,f1,i1, f2,i2。f1是依据 c1生成的,f2同理

上文不是说FastClass可以加快这个方法执行速度嘛,这里是用swtich实现的。i1,i2就是各自fastclass中swtich 中case的数据。由于fastclass是已经生成好的,所以这里的init只是进行了的赋值操作。

初始化结束后进入 fastclass的invoke方法
fci.i2是17, obj 是 小A, args 是参数

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

此时var1 是 17

public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        e58486bf var10000 = (e58486bf)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((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
            case 6:
                return var10000.newInstance((Callback)var3[0]);
            case 7:
                var10000.test1(((Number)var3[0]).intValue());
                return null;
            case 8:
                var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
                return null;
            case 9:
                var10000.setCallbacks((Callback[])var3[0]);
                return null;
            case 10:
                e58486bf.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
                return null;
            case 11:
                e58486bf.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
                return null;
            case 12:
                return var10000.getCallback(((Number)var3[0]).intValue());
            case 13:
                return var10000.getCallbacks();
            case 14:
                return var10000.CGLIB$toString$2();
            case 15:
                return var10000.CGLIB$clone$4();
            case 16:
                return new Boolean(var10000.CGLIB$equals$1(var3[0]));
            case 17:
                var10000.CGLIB$test1$0(((Number)var3[0]).intValue());
                return null;
            case 18:
                return new Integer(var10000.CGLIB$hashCode$3());
            case 19:
                return e58486bf.CGLIB$findMethodProxy((Signature)var3[0]);
            case 20:
                e58486bf.CGLIB$STATICHOOK1();
                return null;
            }
        } catch (Throwable var4) {
            throw new InvocationTargetException(var4);
        }

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

所以整个流程是 执行小A的test1()方法,然后再通过写的代理方法 进入 methoproxy的invokesuper方法中。然后根据生成的数据(数据是 17)找到代理应该执行哪个方法然后快速执行 小A的方法。(有一种空间换时间的想法)

 case 17:
                var10000.CGLIB$test1$0(((Number)var3[0]).intValue());
                return null;

回去看看小A中的方法

	 final void CGLIB$test1$0(int var1) {
        super.test1(var1);
    }

这是因为这种看似多此一举的行为,使得如果将上方的invokesuper如果改成 invoke会死循环。
invoke方法:

    public Object invoke(Object obj, Object[] args) throws Throwable {
        try {
            this.init();
            MethodProxy.FastClassInfo fci = this.fastClassInfo;
            return fci.f1.invoke(fci.i1, obj, args);
        } catch (InvocationTargetException var4) {
            throw var4.getTargetException();
        } catch (IllegalArgumentException var5) {
            if (this.fastClassInfo.i1 < 0) {
                throw new IllegalArgumentException("Protected method: " + this.sig1);
            } else {
                throw var5;
            }
        }
    }

fci.f1.invoke(fci.i1, obj, args)是下方的代码
其中传入的fci.i1是0,obj 是代理对象,args 是参数

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

        try {
            switch(var10001) {
            case 0:
                var10000.test1(((Number)var3[0]).intValue());
                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");
    }

因为上方传入的var2是小A。当invoke拿到小a,fastclass执行 小a中的 test1()。
然后test1()再次进入ProxyForStudent 中再次执行 invoke(),再次拿到小a,再次执行test1()就死循环了…
回顾下小A中test1的代码:this就是小a

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

上方写的有点乱。

Fastclass 是为了 通过 键值快速执行传进来对象的方法的一个类

Methodproxy 中包含
被代理方法的信息,被代理方法在fastclass中的键值,和fastclass
通过被代理方法信息得出键值找出对应的case的方法然后快速执行
invokesuper 是使用被代理类fastclass,所以应该传入代理类
invoke 是使用被代理类的fastclass,所以应该传入被代理类

代理类是则是调用后,根据methodproxy快速执行自己的方法(疑惑行为)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值