JDKProxy和CGLIBProxy的分析

先写一下分析的结论。

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

实现方式:

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

CGLIB不需要接口,不需要传入对象,被代理类需要有public构造器,生成该类的子类,因此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不需要接口,不需要传入对象,被代理类需要public的构造器,生成该类的子类,因此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也动态生成了直接调用的对象,所以速度差不多,甚至可能CGLIB会快一点。
当执行另一个方法时,因为SDKProxy需要生成methodAccessor并执行invoke,CGLIB不需要,所以CGLIB更快。

 

 

 




 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

posted @ 2020-06-15 20:39  lakeslove  阅读(627)  评论(0编辑  收藏  举报