生成署理类文件的办法

jvm增加此启动参数,后边便是署理类class生成的地址 -Dcglib.debugLocation=~/baldhead/java/dynamic-proxy-cglib/src/main/java/com/baldhead/dynamic/proxy/cglib/class

增加这个参数之后,CGLIB就会把生成的署理Class文件存在指定的途径

生成动态署理目标流程

  1. CGLIB首要生成署理类
  2. 代码中的 static 静态代码块 会调用 CGLIB$STATICHOOK1(); 办法,办法效果 3. 新建一个姓名为 CGLIB$THREAD_CALLBACKSThreadLocal,用来存放所设置的 callback 4. 使用反射找到署理类中的一切办法,包括(toStringhashCodeequalsclone),姓名为模板 CGLIB$METHODNAME$数字编号$Method 而且给对应的办法创立署理办法 姓名模板CGLIB$METHODNAME$数字编号$Proxy
  3. 调用结构办法创立署理目标
  4. 然后CGLIB会调用署理目标的 CGLIB$SET_THREAD_CALLBACKS 办法,将传入的 callBack存到 ThreadLocal(CGLIB$THREAD_CALLBACKS) 中去
  5. 后续在目标履行需求署理的办法的时分,就会从CGLIB$THREAD_CALLBACKS中拿到所设置的 CallBack并调用它的intercept()办法

署理目标的创立

static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("com.baldhead.dynamic.proxy.cglib.Impl.UserService$$EnhancerByCGLIB$$e34eec9a");
        Class var1;
        CGLIB$test$0$Method = ReflectUtils.findMethods(new String[]{"test", "()V"}, (var1 = Class.forName("com.baldhead.dynamic.proxy.cglib.Impl.UserService")).getDeclaredMethods())[0];
        CGLIB$test$0$Proxy = MethodProxy.create(var1, var0, "()V", "test", "CGLIB$test$0");
    }

以上代码通过简化的,主要看下面给出的一行 CGLIB$test$0$Proxy = MethodProxy.create(var1, var0, "()V", "test", "CGLIB$test$0"); 对应的办法如下

public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
        /**
         * 这几个参数都可以找到入参目标
         * c1: 被署理类目标的class,也便是原始目标的class
         * c2: 署理类目标的 class
         * desc: 办法的回来值类型
         * name1: 原始署理办法的名称
         * name2: 署理办法在署理类中的名称(CGLIB$test$0)
         */
        MethodProxy proxy = new MethodProxy();
        proxy.sig1 = new Signature(name1, desc);
        proxy.sig2 = new Signature(name2, desc);
        proxy.createInfo = new CreateInfo(c1, c2);
        return proxy;
    }

在MethodProxy中有三个很重要的特点

  • sig1: 表明test办法
  • sig2: 表明 CGLIBtesttest0 办法
  • createInfo: 表明原始类和署理类

invoke和invokeSuper办法

 public Object invoke(Object obj, Object[] args) throws Throwable {
        try {
            this.init();
            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;
            }
        }
    }
    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();
        }
    }

两个办法大差不差的,可是都用到了一个目标 fastClassInfo 这个目标是在 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;
                }
            }
        }
    }

fastClassInfo目标中主要是有四个特点

  • f1: 原始类对应的一个FastClass 署理目标
  • f2: 署理类对应的一个FastClass 署理目标
  • i1: test办法在原始类对应的一个FastClass署理目标中的下标
  • i2: CGLIBtesttest0办法在署理类对应的一个 FastClass 署理目标中的下标 这儿产生了两个署理目标,你说好巧不巧,正好产生的署理,class有3个,其中有两个承继 FastClass, 另外一个承继原始类而且完成 Factory接口

动态代理-cglib分析
其实这两个类相似,都是针对某一个类的FastClass署理类,所以咱们好好看一下UserService所对应的FastClass该类主要有:

  1. 一个结构办法
  2. public int getlndex(Signature var1)
  3. public int getlndex(String var1, Classll var2)
  4. public int getlndex(ClassI var1)
  5. public Object invoke(int var1, Object ar2, Objectll var3)
  6. public Object newlnstance(int var1, Objectll var2)
  7. public int getMaxlndex0

望文生义,FastClass的效果是提高办法的履行速度,依照正常的完成,当咱们调用MethodProxy目标的invokel或invokeSuper0办法时,首要应该要做到的便是找到对应的Method目标,比方:

  1. 履行invoke0,要找到test办法对应的Method目标

  2. 履行invokeSuper0,要找到CGLIBstest$00办法对应的Method目标然后利用反射来履行Method。

那么FastClass的机制便是预先把UserService类或UserService署理类中的一切办法做一个索引,比方:

  public int getIndex(Signature var1) {
        String var10000 = var1.toString();
        switch (var10000.hashCode()) {
            case -2055565910:
                if (var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
                    return 19;
                }
                break;
            case -1659690448:
                if (var10000.equals("CGLIB$test$4()V")) {
                    return 20;
                }
                break;
            case -1457535688:
                if (var10000.equals("CGLIB$STATICHOOK1()V")) {
                    return 12;
                }
                break;
            case -1422510685:
                if (var10000.equals("test()V")) {
                    return 7;
                }
                break;
            case -1411872516:
                if (var10000.equals("CGLIB$hashCode$2()I")) {
                    return 15;
                }
                break;
        // 省略部分代码
        }
        return -1;
    }

一旦调用 getIndex(Signature var1) 办法,就对得到对应办法回来的索引,例如这儿便是test办法回来的对应的索引便是7 再回到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;
                }
            }
        }
    }

init办法中的两个 helper办法便是去生成原始类和署理类的 FactClass署理类,后边个两个getIndex办法 1. 第一个fci.f1.getIndex(this.sig1)便是去获取原始类对应的FastClass署理类中 test办法的下标i1 2. 第二个 fci.f2.getIndex(this.sig2)便是去获取署理类对应的FastClass署理类中testtest0办法的下标i2

然后会把两个下标都记录在 fastClassInfo 目标中

后边便是咱们看到的invokeinvokeSuper中调用的两个办法

  • invoke

    • fci.f1.invoke(fci.i1, obj, args);

      履行原始类对应的FastClass 署理类的invoke办法

  • invokeSuper

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

      履行署理类对应的FastClass署理类的invoke办法

例如: 原始类对应的FastClass 代码

 public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        UserService var10000 = (UserService)var2;
        int var10001 = var1;
        try {
            switch (var10001) {
                case 0:
                    var10000.test();
                    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");
    }

这个代码比较简单,第一个参数便是履行办法的index,第二个参数便是原始类,第三个便是原始类的参数

假如传入的index 是0 ,那么就会去履行test办法

署理类对应的FastClass署理类的invoke办法也是相似

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

例如传入的index 是16 那么履行的便是 var10000.CGLIB$test$0();

假如传入的index是 7 那么履行的便是var10000.test();

var10000 是传入目标强转为UserService..EnhancerByCGLIB..e34eec9a类的目标,UserService..EnhancerByCGLIB..e34eec9a类其实便是UserService的署理类

invokeSuper结论

所以当咱们履行invokeSuper办法的时分,不能传入原始类(UserService)只能传入署理类目标,否则就无法转换成为署理类类型

所以FastClass 快的地方便是预先把一切的办法信息都生成了对应的index,在真实的去履行的时分不用再去找Method目标,直接传入对应办法的index就可以直接履行对应的办法了