• JDKProxy和CGLIBProxy的分析


    先写一下分析的结论。

    我们比较一下SKDProxy和CGLIBProxy的区别:
    
    实现方式:
    
    SKDProxy需要接口,需要传入对象,不需要无参构造器,生成该接口的实现类。
    
    CGLIB不需要接口,不需要传入对象,需要无参构造器,生成该类的子类,因此CGLIB无法代理final方法,也无法代理定制对象。
    
    比较:
    
    1、生成代理类的源码,SDKProxy生成的是实现类,CGLIB生成的是子类,
    
    2、当我们执行Method A的invoke方法时,
    
    SDKProxy的方式是
    
    Object obj = method.invoke(this.target,args);
    该方法第一次执行是,需要生成methodAccessor,这个生成很快。第16次执行时,需要生成字节码,会慢一下。
    第二次执行不需要生成MethodAccessor。但是执行另一方方法时,依然需要methodAccessor。
    CGLIBProxy的执行方式有两种:
    
    1、Object obj = method.invoke(method.getDeclaringClass().newInstance(),args);
    那么就是普通的反射调用,注意,不能用o做参数,因为会造成死循环。

    这种方式,和SDKProxy一样,因为CGLIB生成的代理类也把method对象存为类变量,所以执行效率也一样。

    2、Object obj = methodProxy.invokeSuper(o,objects); 这种方式,第一次执行时,会生成两个fast类,因此比sdkproxy慢,
    第二次执行该方法,因为SDKProxy需要执行invoke,所以CGLIB更快。
    当执行另一个方法时,因为SDKProxy需要生成methodAccessor并执行invoke,所以CGLIB更快。

     代理模式

    在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。

    在代理模式中,我们创建持有现有对象(可以用该类的接口)的代理对象,以便向外界提供功能接口。

    JDK动态代理:$Proxy0是动态生成的,这个实现了盒子套盒子。


    Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    关于这个方法的参数,
    1、用clazz.getInterfaces()是用来生成$Proxy0.java用的,
    2、把
    $Proxy0.java编译成$Proxy0.class
    3、用
    clazz.getClassLoader()是用来把$Proxy0.class文件加载进jvm(Class proxyClass = classLoader.findClass("$Proxy0");

    4、加载文件时,执行$Proxy0的static代码块,把所有的非final方法以及Object的equals,hashcode,toString方法都加载成 类变量
    5、获取$Proxy0的带参构造函数,并把 this(被代理对象) 设置进$Proxy0

    当我们调用$Proxy0的findLove()时,执行的如下:
    public final class $Proxy0 extends Proxy implements Person {
      private static Method m1;
      private static Method m3;
      private static Method m2;
      private static Method m0;
    
      public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
      }
    
      public final boolean equals(Object var1) throws  {
        try {
          return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
          throw var3;
        } catch (Throwable var4) {
          throw new UndeclaredThrowableException(var4);
        }
      }
    
      public final void findLove() throws  {
        try {
          super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
          throw var2;
        } catch (Throwable var3) {
          throw new UndeclaredThrowableException(var3);
        }
      }
    
      public final String toString() throws  {
        try {
          return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
          throw var2;
        } catch (Throwable var3) {
          throw new UndeclaredThrowableException(var3);
        }
      }
    
      public final int hashCode() throws  {
        try {
          return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
          throw var2;
        } catch (Throwable var3) {
          throw new UndeclaredThrowableException(var3);
        }
      }
    
      static {
        try {
          m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
          m3 = Class.forName("com.gupaoedu.vip.pattern.proxy.Person").getMethod("findLove");
          m2 = Class.forName("java.lang.Object").getMethod("toString");
          m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
          throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
          throw new NoClassDefFoundError(var3.getMessage());
        }
      }
    }
      protected Proxy(InvocationHandler h) {
            Objects.requireNonNull(h);
            this.h = h;
        }

    此时我们执行代理类的findLove方法,执行的是这个:

     super.h.invoke(this, m3, (Object[])null);
    这里需要注意的是,m3这个参数是静态变量,而不是反射获得,因此效率很快。

    而h.invoke方法的实现如下:

    invoke(Object proxy, Method method, Object[] args) 
    这个invoke的三个参数都是什么呢?
    从$Proxy0.class可以看出,
    Object proxy 就是$Proxy0的实例对象,
    Method method 是被代理类的method方法对象
    Object[] args 这里看不出来,从源码里看,args是第二个参数method对象的参数
    
    
    public class JDKMeipo implements InvocationHandler {

    private Object target;
    public Object getInstance(Object person) throws Exception{
    this.target = person;
    Class<?> clazz = target.getClass();
    //System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); //设置系统属性
    return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    before();
    Object obj = method.invoke(this.target,args);
    after();
    return obj;
    }

    private void before(){
    System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
    System.out.println("开始物色");
    }

    private void after(){
    System.out.println("OK的话,准备办事");
    }
    }

    我们看一下Object obj = method.invoke(this.target,args);的执行

        public Object invoke(Object obj, Object... args)
            throws IllegalAccessException, IllegalArgumentException,
               InvocationTargetException
        {
            if (!override) {
                if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                    Class<?> caller = Reflection.getCallerClass();
                    checkAccess(caller, clazz, obj, modifiers);
                }
            }
            MethodAccessor ma = methodAccessor;             // read volatile
            if (ma == null) {
                ma = acquireMethodAccessor();
            }
            return ma.invoke(obj, args);
        }

    重点看ma = acquireMethodAccessor();和return ma.invoke(obj, args);

    先看ma = acquireMethodAccessor();

        // NOTE that there is no synchronization used here. It is correct
        // (though not efficient) to generate more than one MethodAccessor
        // for a given Method. However, avoiding synchronization will
        // probably make the implementation more scalable.
        private MethodAccessor acquireMethodAccessor() {
            // First check to see if one has been created yet, and take it
            // if so
            MethodAccessor tmp = null;
            if (root != null) tmp = root.getMethodAccessor();
            if (tmp != null) {
                methodAccessor = tmp;
            } else {
                // Otherwise fabricate one and propagate it up to the root
                tmp = reflectionFactory.newMethodAccessor(this);//这个方法是重点
                setMethodAccessor(tmp);
            }
    
            return tmp;
        }
      
    private static boolean noInflation = false;
    private static int inflationThreshold = 15;
    public MethodAccessor newMethodAccessor(Method var1) {
        checkInitted();
        if (noInflation && !ReflectUtil.isVMAnonymousClass(var1.getDeclaringClass())) {
          return (new MethodAccessorGenerator()).generateMethod(var1.getDeclaringClass(), var1.getName(), var1.getParameterTypes(), var1.getReturnType(), var1.getExceptionTypes(), var1.getModifiers());
        } else {
          NativeMethodAccessorImpl var2 = new NativeMethodAccessorImpl(var1);
          DelegatingMethodAccessorImpl var3 = new DelegatingMethodAccessorImpl(var2);
          var2.setParent(var3);
          return var3;
        }
      }
    class NativeMethodAccessorImpl extends MethodAccessorImpl {
      private final Method method;
      private DelegatingMethodAccessorImpl parent;
      private int numInvocations;
    
      NativeMethodAccessorImpl(Method var1) {
        this.method = var1;
      }
    
      public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
        if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
          MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
          this.parent.setDelegate(var3);
        }
    
        return invoke0(this.method, var1, var2);
      }
    
      void setParent(DelegatingMethodAccessorImpl var1) {
        this.parent = var1;
      }
    
      private static native Object invoke0(Method var0, Object var1, Object[] var2);
    }
    class DelegatingMethodAccessorImpl extends MethodAccessorImpl {
      private MethodAccessorImpl delegate;
    
      DelegatingMethodAccessorImpl(MethodAccessorImpl var1) {
        this.setDelegate(var1);
      }
    
      public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
        return this.delegate.invoke(var1, var2);
      }
    
      void setDelegate(MethodAccessorImpl var1) {
        this.delegate = var1;
      }
    }

    我对delegate和proxy目前分不清,所以这里不区分,只看实现方式:

    最开始,DMAI用delegate属性持有了NMAI,并且NMAI也用parent属性持有了DMAI,并把DMAI返回。

    每次执行DMAI执行invoke()方法时, 实际执行的时delegate属性的invoke方法,也就是执行了NMAI的invoke方法。

    当NMAI的invoke方法执行超过15次以后,NMAI生成了MagicAccessorImpl对象,并把DMAI的delete改为MagicAccessorImpl,变成了如下:

    以后DMAI执行invoke方法时,实际执行的时delegate属性的invoke方法,也就是执行了MagicAccessorImpl的invoke方法。

    为什么要设置这个15呢?因为native的invoke方法执行比较快,但是JVM无法优化,少量执行时可以的,

    如果大量执行,那么还是JVM会用MagicAccessorImpl,因为可以被JVM优化,从而效率上高于native的invoker方法

    继续看ma.invoke(obj, args)

    如上分析所示,如果时NMAI的invoke方法,执行的时本地方法,无法查看。

    当超过15次以后,用的时ASM生成的字节码

    所以,当method A执行invoke时,会生成method A的MethodAccessor,当method A再次执行时,会使用一前的MethodAccessor。

    但是当method B执行invoke时,会继续生成method B的MethodAccessor。

    生成字节码如下(用的是阿里巴巴的arthas进行运行时反编译捕获到的)

    从动态生成的字节码对象GeneratedMethodAccessor1可以看出,该对象赋值给了delegate,

    当调用invoke方法时,实际上调用的是GeneratedMethodAccessor1的invoke方法,该方法直接调用了被反射调用的方法。

    但是也可以看到,这个只是针对这一个方法的,MagicAccessorImpl的不同方法不会复用MethodAccessor,字节码也会重新生成。

    /*
     * Decompiled with CFR.
     * 
     * Could not load the following classes:
     *  com.lxtest.springbootdemo.invoke.InvokeTest
     */
    package sun.reflect;
    
    import com.lxtest.springbootdemo.invoke.InvokeTest;
    import java.lang.reflect.InvocationTargetException;
    import sun.reflect.MethodAccessorImpl;
    
    public class GeneratedMethodAccessor1 extends MethodAccessorImpl {
        /*
         * Loose catch block
         * Enabled aggressive block sorting
         * Enabled unnecessary exception pruning
         * Enabled aggressive exception aggregation
         * Lifted jumps to return sites
         */
        public Object invoke(Object object, Object[] arrobject) throws InvocationTargetException {
            InvokeTest invokeTest;
            block5: {
                if (object == null) {
                    throw new NullPointerException();
                }
                invokeTest = (InvokeTest)object;
                if (arrobject == null || arrobject.length == 0) break block5;
                throw new IllegalArgumentException();
            }
            try {
                invokeTest.t1();
                return null;
            }
            catch (Throwable throwable) {
                throw new InvocationTargetException(throwable);
            }
            catch (ClassCastException | NullPointerException runtimeException) {
                throw new IllegalArgumentException(super.toString());
            }
        }
    }

     CGLib使用起来要比JDKProxy简单一些:如下:

    public class CGlibMeipo implements MethodInterceptor {
        public Object getInstance(Class<?> clazz) throws Exception{
            //相当于Proxy,代理的工具类
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(clazz);
            enhancer.setCallback(this);
            return enhancer.create();
        }
    
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            before();
            method.invoke(method.getDeclaringClass().newInstance(),objects);
            Object obj = methodProxy.invokeSuper(o,objects);
            after();
            return obj;
        }
    
        private void before(){
            System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
            System.out.println("开始物色");
        }
    
        private void after(){
            System.out.println("OK的话,准备办事");
        }
    }

    cglib构建不需要new一个对象,直接传类对象即可,但是这样会导致一个问题,那就是无法定制代理对象

    当执行enhancer.create();时,生成代理类对象

    Customer$$EnhancerByCGLIB$$e1de0c0c extends Customer implements Factory

    这个对象初始化过程如下:

      static {
        CGLIB$STATICHOOK1();
      }
     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$findLove$0$Method;
      private static final MethodProxy CGLIB$findLove$0$Proxy;
      private static final Object[] CGLIB$emptyArgs;
      private static final Method CGLIB$finalize$1$Method;
      private static final MethodProxy CGLIB$finalize$1$Proxy;
      private static final Method CGLIB$equals$2$Method;
      private static final MethodProxy CGLIB$equals$2$Proxy;
      private static final Method CGLIB$toString$3$Method;
      private static final MethodProxy CGLIB$toString$3$Proxy;
      private static final Method CGLIB$hashCode$4$Method;
      private static final MethodProxy CGLIB$hashCode$4$Proxy;
      private static final Method CGLIB$clone$5$Method;
      private static final MethodProxy CGLIB$clone$5$Proxy;
    
      static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("com.gupaoedu.vip.pattern.proxy.dynamicproxy.cglibproxy.Customer$$EnhancerByCGLIB$$e1de0c0c");
        Class var1;
        CGLIB$findLove$0$Method = ReflectUtils.findMethods(new String[]{"findLove", "()V"}, (var1 = Class.forName("com.gupaoedu.vip.pattern.proxy.dynamicproxy.cglibproxy.Customer")).getDeclaredMethods())[0];
        CGLIB$findLove$0$Proxy = MethodProxy.create(var1, var0, "()V", "findLove", "CGLIB$findLove$0");
        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$1$Method = var10000[0];
        CGLIB$finalize$1$Proxy = MethodProxy.create(var1, var0, "()V", "finalize", "CGLIB$finalize$1");
        CGLIB$equals$2$Method = var10000[1];
        CGLIB$equals$2$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
        CGLIB$toString$3$Method = var10000[2];
        CGLIB$toString$3$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
        CGLIB$hashCode$4$Method = var10000[3];
        CGLIB$hashCode$4$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$4");
        CGLIB$clone$5$Method = var10000[4];
        CGLIB$clone$5$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
      }

    该过程把被代理类和代理类里面的方法一一对应的绑定在一堆MethodProxy中。这些方法包括代理类的方法findLove和Object的所有public方法。

    我们看一下该过程:

    上面代码里的var0是生成的代理类Customer$$Enhancerxxxxx,var1是被代理类Customer

    这里我们重点看一个对象:MethodProxy

    CGLIB$findLove$0$Proxy = MethodProxy.create(var1, var0, "()V", "findLove", "CGLIB$findLove$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);
            proxy.sig2 = new Signature(name2, desc);
            proxy.createInfo = new CreateInfo(c1, c2);
            return proxy;
        }

     记住sig1代表findLove, sig2代表CGLIB$findLove$0

        private static class CreateInfo{
            Class c1;
            Class c2;
            NamingPolicy namingPolicy;
            GeneratorStrategy strategy;
            boolean attemptLoad;
            public CreateInfo(Class c1, Class c2)
            {
                this.c1 = c1;
                this.c2 = c2;
                AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();//获取代码生成器
                if (fromEnhancer != null) {
                    namingPolicy = fromEnhancer.getNamingPolicy();
                    strategy = fromEnhancer.getStrategy();
                    attemptLoad = fromEnhancer.getAttemptLoad();
                }
            }
        }

    所以,我们知悉这个生成的MethodProxy信息如下:

    public class MethodProxy {
        private Signature sig1;//findLove
        private Signature sig2;//CGLIB$findLove$0
        private CreateInfo createInfo;//c1是被代理类Customer,c2是生成的代理类Customer$$Enhancerxxxxx,还有一个代码生成器,
    private final Object initLock = new Object(); 

    private volatile FastClassInfo fastClassInfo;

    之后我们看一下该代理类默认的构造方法:主要是把我们传入的MethodInterceptor(被放入了threadLocal变量里)设置到该代理类中,供以后回调

     public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)
     public Customer$$EnhancerByCGLIB$$e1de0c0c() {
        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) {
        Customer$$EnhancerByCGLIB$$e1de0c0c var1 = (Customer$$EnhancerByCGLIB$$e1de0c0c)var0;
        if (!var1.CGLIB$BOUND) {
          var1.CGLIB$BOUND = true;
          Object var10000 = CGLIB$THREAD_CALLBACKS.get();
          if (var10000 == null) {
            var10000 = CGLIB$STATIC_CALLBACKS;
            if (CGLIB$STATIC_CALLBACKS == null) {
              return;
            }
          }
          var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }
    
      }

    当我们调用生成的代理类的findLove方法时,过程怎样呢?实际调用的是MethodInterceptor的intercept方法

      final void CGLIB$findLove$0() {
        super.findLove();
      }
    
      public final void findLove() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (this.CGLIB$CALLBACK_0 == null) {
          CGLIB$BIND_CALLBACKS(this);
          var10000 = this.CGLIB$CALLBACK_0;
        }
    
        if (var10000 != null) {
          var10000.intercept(this, CGLIB$findLove$0$Method, CGLIB$emptyArgs, CGLIB$findLove$0$Proxy);
        } else {
          super.findLove();
        }
      }

    该方法的几个参数分别代表什么呢?

        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            before();
            method.invoke(method.getDeclaringClass().newInstance(),objects);
            Object obj = methodProxy.invokeSuper(o,objects);
            after();
            return obj;
        }

    Object o 是被生成的代理对象Customer$$Enhancerxxxxx

    Method method 是 Customer的findLove方法对象。

    Object[] objects 是 findLove的参数

    MethodProxy methodProxy 含义如下:

    public class MethodProxy {
        private Signature sig1;//findLove
        private Signature sig2;//CGLIB$findLove$0
        private CreateInfo createInfo;//包含c1、c2、和一个代码生成器,其中c1是被代理类Customer,c2是生成的代理类Customer$$Enhancerxxxxx
    private final Object initLock = new Object(); 
    private volatile FastClassInfo fastClassInfo;

    此时,我们在intercept方法中调用原始方法:

    如果像jdk那么写:

    Object obj = method.invoke(method.getDeclaringClass().newInstance(),objects);
    那么就是普通的反射调用,注意,不能用o做参数,因为会造成死循环。

    此时CGLIB不会生成fast类

    如果这样写:

    Object obj = methodProxy.invokeSuper(o,objects);
    CGLIB会生成customer的fast类,和Customer$$Enhancerxxxxx的fast类

    看一下执行过程:

        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) {
                throw e.getTargetException();
            }
        }

    先看初始化:

        private void init()
        {
            /* 
             * Using a volatile invariant allows us to initialize the FastClass and
             * method index pairs atomically.
             * 
             * Double-checked locking is safe with volatile in Java 5.  Before 1.5 this 
             * code could allow fastClassInfo to be instantiated more than once, which
             * appears to be benign.
             */
            if (fastClassInfo == null)
            {
                synchronized (initLock)
                {
                    if (fastClassInfo == null)
                    {
                        CreateInfo ci = createInfo;
    
                        FastClassInfo fci = new FastClassInfo();
                //生成customer的fast类,和Customer$$Enhancerxxxxx的fast类 fci.f1
    = helper(ci, ci.c1);//c1是customer,f1是customer的fast类
                fci.f2 = helper(ci, ci.c2);//c2是生成的customer代理类 ,f2是代理类的fast类
                fci.i1
    = fci.f1.getIndex(sig1);
                fci.i2
    = fci.f2.getIndex(sig2);
                fastClassInfo
    = fci;
             }
           }
          }
        }
     
    private static FastClass helper(CreateInfo ci, Class type) {
    FastClass.Generator g = new FastClass.Generator();
    g.setType(type);
    g.setClassLoader(ci.c2.getClassLoader());
    g.setNamingPolicy(ci.namingPolicy);
    g.setStrategy(ci.strategy);
    g.setAttemptLoad(ci.attemptLoad);
    return g.create();//生成fast类,这里需要注意的是,默认是useCache=ture,如果fast存在则不会二次生成fast类,如果改为false,则会重新生成fast类
    }

    private static class FastClassInfo
    {
    FastClass f1;
    FastClass f2;
    int i1;
    int i2;
    }
     

    之后看一下这两行代码执行了啥:

    fci.i1 = fci.f1.getIndex(sig1);
    fci.i2 = fci.f2.getIndex(sig2);
    看一下fci.i1 = fci.f1.getIndex(sig1);
    public int getIndex(Signature var1) {
        String var10000 = var1.toString();//name+desc,也就是findLove()V
        switch(var10000.hashCode()) { //findLove()V的hashCode是1192015562
        case -1725733088:
          if (var10000.equals("getClass()Ljava/lang/Class;")) {
            return 7;
          }
          break;
        case 1192015562:
          if (var10000.equals("findLove()V")) {
            return 0;
          }
          break;
        case 1826985398:
          if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
            return 4;
          }
          break;case 1913648695:
          if (var10000.equals("toString()Ljava/lang/String;")) {
            return 5;
          }
          break;
        case 1984935277:
          if (var10000.equals("hashCode()I")) {
            return 6;
          }
        }
    //我在这里删除了无关的方法的代码,其实还有好多,像wait,notify等
        return -1;
      }

    于是我们得到fci.i1=0,同理,可以得到fci.i2=8;

    于是,我们执行了init()后,得到如下信息:

    如果fastClassInfo不存在,则初始化,如果存在则跳过

    private static class FastClassInfo
    {
        FastClass f1;//f1是customer的fast类
       FastClass f2;//f2是代理类的fast类

      
    int i1; //0 findLove()V的索引
       int i2; //8 CGLIB$findLove0()V的索引
    }

    查看

    fci.f2.invoke(fci.i2, obj, args);//i2是8,obj是被生成的代理对象Customer$$Enhancerxxxxx,args是 findLove的参数
    public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
        e1de0c0c var10000 = (e1de0c0c)var2;
        int var10001 = var1;//8
    
        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 6:
            var10000.findLove();
            return null;
          case 7:
            return e1de0c0c.CGLIB$findMethodProxy((Signature)var3[0]);
          case 8:
            var10000.CGLIB$findLove$0();//var10000就是被生成的代理对象Cuseomer$$Enhancerxxxxx
            return null;
          ...case 26:
            var10000.notifyAll();
            return null;
          }
        } catch (Throwable var4) {
          throw new InvocationTargetException(var4);
        }
        throw new IllegalArgumentException("Cannot find matching method/constructor");
      }

    查看Cuseomer$$Enhancerxxxxx类的CGLIB$findLove$0()

     final void CGLIB$findLove$0() {
        super.findLove();
      }

    因为super是customer,所以调用类customer的findLove()方法,通过在fast类里对方法加索引的方案,避开了反射调用,因此提高了效率。

    这也是为何CGLIBProxy比JDKProxy效率高的原因。

    我们比较一下SKDProxy和CGLIBProxy的区别:

    实现方式:

    SKDProxy需要接口,需要传入对象,不需要无参构造器,生成该接口的实现类。

    CGLIB不需要接口,不需要传入对象,需要无参构造器,生成该类的子类,因此CGLIB无法代理final方法。

    比较:

    1、生成代理类的源码,SDKProxy生成的是实现类,CGLIB生成的是子类,

    2、当我们执行Method A的invoke方法时,

    SDKProxy的方式是

    Object obj = method.invoke(this.target,args);
    该方法第一次执行是,需要生成methodAccessor,这个生成很快。第16次执行时,需要生成字节码,会慢一下。
    第二次执行不需要生成MethodAccessor。但是执行另一方方法时,依然需要methodAccessor。

    CGLIBProxy的执行方式有两种:

    1、Object obj = method.invoke(method.getDeclaringClass().newInstance(),objects);
    那么就是普通的反射调用,注意,不能用o做参数,因为会造成死循环。

    这种方式,和SDKProxy一样,因为CGLIB生成的代理类也把method对象存为类变量,所以执行效率也一样。

    2、Object obj = methodProxy.invokeSuper(o,objects);
    这种方式,第一次执行时,会生成两个fast类,因此比sdkproxy慢,
    第二次执行该方法,因为SDKProxy需要执行invoke,所以CGLIB更快。
    第无数次执行时,因为SDKProxy也动态生成了直接调用的对象,所以速度差不多,甚至可能SDKProxy会快一点。
    当执行另一个方法时,因为SDKProxy需要生成methodAccessor并执行invoke,CGLIB不需要,所以CGLIB更快。
    
    
    
    
    



    ------------恢复内容结束------------

  • 相关阅读:
    深入理解计算机系统 第十章 系统级I/O
    深入理解计算机系统 第九章 虚拟内存(1)
    Leetcode练习(Python):第520题:检测大写字母:给定一个单词,你需要判断单词的大写使用是否正确。 我们定义,在以下情况时,单词的大写用法是正确的: 全部字母都是大写,比如"USA"。 单词中所有字母都不是大写,比如"leetcode"。 如果单词不只含有一个字母,只有首字母大写, 比如 "Google"。 否则,我们定义这个单词没有正确使用大写字母。
    Leetcode练习(Python):第461题:汉明距离:两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。 给出两个整数 x 和 y,计算它们之间的汉明距离。
    Leetcode练习(Python):第485题:最大连续1的个数:给定一个二进制数组, 计算其中最大连续1的个数。
    Leetcode练习(Python):第412题:Fizz Buzz:写一个程序,输出从 1 到 n 数字的字符串表示。 1. 如果 n 是3的倍数,输出“Fizz”; 2. 如果 n 是5的倍数,输出“Buzz”; 3.如果 n 同时是3和5的倍数,输出 “FizzBuzz”。
    Leetcode练习(Python):第383题:赎金信:给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串 ransom 能不能由第二个字符串 magazines 里面的字符构成。如果可以构成,返回 true ;否则返回 false。
    Leetcode练习(Python):第392题:判断子序列:给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
    Leetcode练习(Python):第387题:字符串中的第一个唯一字符:给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。
    Leetcode练习(Python):第371题:两整数之和:不使用运算符 + 和
  • 原文地址:https://www.cnblogs.com/lakeslove/p/13137694.html
Copyright © 2020-2023  润新知