JAVA动态代理

  • 静态代理的代理关系在编译时就确定了,而动态代理的代理关系是在运行期确定的。静态代理实现简单,适合于代理类较少且确定的情况,而动态代理则给我们提供了更大的灵活性
  • JDK原生动态代理是Java原生支持的,不需要任何外部依赖,但是它只能基于接口进行代理;CGLIB通过继承的方式进行代理,无论目标对象有没有实现接口都可以代理,但是无法处理final、private方法
  • CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些
  • jdk采用反射机制调用委托类的方法,cglib采用类似索引的方式直接调用委托类方法

标签(空格分隔): jdk动态代理 cglib

## jdk动态代理

jdk动态代理机制中,有两个重要的类或接口,一个是Proxy,另一个是
InvocationHandler

Proxy类

Proxy类是用来动态创建一个代理对象,经常使用newProxyInstance静态方法

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException  
参数:
loader 类加载器  
interfaces 真实类所拥有的所有接口的数组  
h 调用处理器对象  

InvocationHandler接口

InvocationHandler接口只有唯一一个invoke方法

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;  
参数:
proxy 代理类对象  
method 调用真实类对象某个方法对应的method对象  
args 调用真实类对象某个方法传入的参数  

示例

1、主题接口

package com.example.ford.proxy;

public interface Subject {  
    String sayHello(String name);
    String sayGoodBye();
}

2、 被代理类

package com.example.ford.proxy;

public class RealSubject implements Subject{  
    @Override
    public String sayHello(String name) {
        return "hello "+name;
    }

    @Override
    public String sayGoodBye() {
        return " good bye";
    }
}

3、调用处理器

package com.example.ford.proxy;

import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;

public class TestInvocationHandler implements InvocationHandler{  
    private Subject subject;

    public TestInvocationHandler(Subject subject){
        this.subject = subject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(proxy.getClass());
        System.out.println("开始执行 "+method.getName());
        Object returnValue = method.invoke(subject,args);
        System.out.println("结束执行 "+method.getName());
        return returnValue;
    }
}

3、测试

package com.example.ford.proxy;

import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Proxy;

public class TestMain {  
    public  static void main(String[] args) {
        Subject subject = new RealSubject();
        InvocationHandler handler = new TestInvocationHandler(subject);
        Class cls = subject.getClass();
        ClassLoader loader = cls.getClassLoader();
        Class[] interfaces = cls.getInterfaces();
        Subject proxy = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);
        String returnValue1 = proxy.sayHello("changfeng");
        System.out.println(returnValue1);
        String returnValue2 = proxy.sayGoodBye();
        System.out.println(returnValue2);
    }
}

测试结果

class com.sun.proxy.$Proxy0  
开始执行 sayHello
结束执行 sayHello
hello changfeng  
class com.sun.proxy.$Proxy0  
开始执行 sayGoodBye
结束执行 sayGoodBye
 good bye

原理分析

生成代理类类文件:

package com.example.ford.proxy;

import sun.misc.ProxyGenerator;

import java.io.File;  
import java.io.FileNotFoundException;  
import java.io.FileOutputStream;  
import java.io.IOException;  
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Proxy;

public class JDKProxyTest {  
    public static void main(String[] args){
        Subject subject = new RealSubject();
        InvocationHandler handler = new TestInvocationHandler(subject);
        Class cls = subject.getClass();
        ClassLoader loader = cls.getClassLoader();
        Class[] interfaces = cls.getInterfaces();
        Subject proxy = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);

        createProxyClassFile();
    }

    private static void createProxyClassFile(){
        String name = "ProxySubject";
        byte[] data = ProxyGenerator.generateProxyClass(name,new Class[]{Subject.class});
        FileOutputStream out =null;
        try {
            out = new FileOutputStream(name+".class");
            System.out.println((new File("hello")).getAbsolutePath());
            out.write(data);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(null!=out) try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

利用jd-gui反编译代理类class文件,可以发现最终生成的代理类继承Proxy类、实现Subject接口,代理类实现了Subject接口的sayHello方法、sayGoodBye方法,在实现Subject接口方法的内部,通过反射调用了InvocationHandlerImpl的invoke方法

import com.example.ford.proxy.Subject;  
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
import java.lang.reflect.Proxy;  
import java.lang.reflect.UndeclaredThrowableException;

public final class ProxySubject  
  extends Proxy
  implements Subject
{
  private static Method m1;
  private static Method m3;
  private static Method m2;
  private static Method m4;
  private static Method m0;

  public ProxySubject(InvocationHandler paramInvocationHandler)
  {
    super(paramInvocationHandler);
  }

  public final boolean equals(Object paramObject)
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final String sayHello(String paramString)
  {
    try
    {
      return (String)this.h.invoke(this, m3, new Object[] { paramString });
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final String toString()
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final String sayGoodBye()
  {
    try
    {
      return (String)this.h.invoke(this, m4, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final int hashCode()
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("com.example.ford.proxy.Subject").getMethod("sayHello", new Class[] { Class.forName("java.lang.String") });
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m4 = Class.forName("com.example.ford.proxy.Subject").getMethod("sayGoodBye", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

注意:对于从Object中继承的方法,JDK Proxy会把hashCode()、equals()、toString()这三个非接口方法转发给InvocationHandler,其余的Object方法则不会转发

## cglib动态代理

cglib动态代理必须实现MethodInterceptor接口

MethodInterceptor接口

package org.springframework.cglib.proxy;

import java.lang.reflect.Method;

public interface MethodInterceptor extends Callback {  
    Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
    参数1 代理对象
    参数2 方法对象
    参数3 方法参数
    参数4 方法对应的
}

示例

package com.example.ford.proxy;

import org.springframework.cglib.proxy.Enhancer;  
import org.springframework.cglib.proxy.MethodInterceptor;  
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor{  
    private Enhancer enhancer = new Enhancer();
    public Object getProxy(Class cls){
        enhancer.setSuperclass(cls);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println(o.getClass());
        System.out.println("开始执行 "+method.getName());
        //我们一般使用proxy.invokeSuper(obj,args)方法。这个很好理解,就是执行原始类的方法。还有一个方法proxy.invoke(obj,args),这是执行生成子类的方法。
        //如果传入的obj就是子类的话,会发生内存溢出,因为子类的方法不停地进入intercept方法,而这个方法又去调用子类的方法,两个方法直接循环调用了。
        Object returnValue = methodProxy.invokeSuper(o,objects);
        //Object returnValue = methodProxy.invoke(o,objects);
        System.out.println("结束执行 "+method.getName());
        return returnValue;
    }

    public static void main(String[] args){
        CglibProxy cglibProxy = new CglibProxy();
        RealSubject realSubject = (RealSubject)cglibProxy.getProxy(RealSubject.class);
        Object returnValue1 = realSubject.sayHello("changfeng");
        System.out.println(returnValue1);
        Object returnValue2 = realSubject.sayGoodBye();
        System.out.println(returnValue2);
    }
}

注意:对于从Object中继承的方法,CGLIB代理也会进行代理,如hashCode()、equals()、toString()等,但是getClass()、wait()等方法不会,因为它是final方法,CGLIB无法代理

注意:既然是继承就不得不考虑final的问题。我们知道final类型不能有子类,所以CGLIB不能代理final类型,遇到这种情况会抛出类似如下异常:

java.lang.IllegalArgumentException: Cannot subclass final class cglib.HelloConcrete

注意:同样的,final方法是不能重载的,所以也不能通过CGLIB代理,遇到这种情况不会抛异常,而是会跳过final方法只代理其他方法。

源码分析

通过以下方式可以生成代理类class文件 System.setProperty(DebuggingClassWriter.DEBUGLOCATIONPROPERTY, "C:\\Code\\whywhy\\target\\classes\\zzzzzz")

用jd-gui反编译代理类

package com.example.ford.proxy;

import java.lang.reflect.Method;  
import org.springframework.cglib.proxy.Callback;  
import org.springframework.cglib.proxy.Factory;  
import org.springframework.cglib.proxy.MethodInterceptor;  
import org.springframework.cglib.proxy.MethodProxy;

public class RealSubject$$EnhancerByCGLIB$$6a387257  
  extends RealSubject
  implements Factory
{
  private boolean CGLIB$BOUND;
  public static Object CGLIB$FACTORY_DATA;
  private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
  private static final Callback[] CGLIB$STATIC_CALLBACKS;
  private MethodInterceptor CGLIB$CALLBACK_0;
  private static Object CGLIB$CALLBACK_FILTER;
  private static final Method CGLIB$sayHello$0$Method;
  private static final MethodProxy CGLIB$sayHello$0$Proxy;
  private static final Object[] CGLIB$emptyArgs;
  private static final Method CGLIB$sayGoodBye$1$Method;
  private static final MethodProxy CGLIB$sayGoodBye$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;

  /* Error */
  static void CGLIB$STATICHOOK1()
  {
    // Byte code:
    //   0: new 22    java/lang/ThreadLocal
    //   3: dup
    //   4: invokespecial 25    java/lang/ThreadLocal:<init>    ()V
    //   7: putstatic 27    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$THREAD_CALLBACKS   Ljava/lang/ThreadLocal;
    //   10: iconst_0
    //   11: anewarray 48    java/lang/Object
    //   14: putstatic 69    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$emptyArgs  [Ljava/lang/Object;
    //   17: ldc -108
    //   19: invokestatic 154    java/lang/Class:forName (Ljava/lang/String;)Ljava/lang/Class;
    //   22: astore_0
    //   23: iconst_4
    //   24: anewarray 58    java/lang/String
    //   27: dup
    //   28: iconst_0
    //   29: ldc -101
    //   31: aastore
    //   32: dup
    //   33: iconst_1
    //   34: ldc -100
    //   36: aastore
    //   37: dup
    //   38: iconst_2
    //   39: ldc -99
    //   41: aastore
    //   42: dup
    //   43: iconst_3
    //   44: ldc -98
    //   46: aastore
    //   47: ldc -96
    //   49: invokestatic 154    java/lang/Class:forName (Ljava/lang/String;)Ljava/lang/Class;
    //   52: dup
    //   53: astore_1
    //   54: invokevirtual 164    java/lang/Class:getDeclaredMethods  ()[Ljava/lang/reflect/Method;
    //   57: invokestatic 170    org/springframework/cglib/core/ReflectUtils:findMethods ([Ljava/lang/String;[Ljava/lang/reflect/Method;)[Ljava/lang/reflect/Method;
    //   60: dup
    //   61: iconst_0
    //   62: aaload
    //   63: putstatic 46    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$sayHello$0$Method    Ljava/lang/reflect/Method;
    //   66: aload_1
    //   67: aload_0
    //   68: ldc -100
    //   70: ldc -101
    //   72: ldc -85
    //   74: invokestatic 177    org/springframework/cglib/proxy/MethodProxy:create  (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/springframework/cglib/proxy/MethodProxy;
    //   77: putstatic 50    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$sayHello$0$Proxy Lorg/springframework/cglib/proxy/MethodProxy;
    //   80: dup
    //   81: iconst_1
    //   82: aaload
    //   83: putstatic 67    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$sayGoodBye$1$Method  Ljava/lang/reflect/Method;
    //   86: aload_1
    //   87: aload_0
    //   88: ldc -98
    //   90: ldc -99
    //   92: ldc -78
    //   94: invokestatic 177    org/springframework/cglib/proxy/MethodProxy:create  (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/springframework/cglib/proxy/MethodProxy;
    //   97: putstatic 71    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$sayGoodBye$1$Proxy   Lorg/springframework/cglib/proxy/MethodProxy;
    //   100: pop
    //   101: bipush 8
    //   103: anewarray 58    java/lang/String
    //   106: dup
    //   107: iconst_0
    //   108: ldc -77
    //   110: aastore
    //   111: dup
    //   112: iconst_1
    //   113: ldc -76
    //   115: aastore
    //   116: dup
    //   117: iconst_2
    //   118: ldc -75
    //   120: aastore
    //   121: dup
    //   122: iconst_3
    //   123: ldc -98
    //   125: aastore
    //   126: dup
    //   127: iconst_4
    //   128: ldc -74
    //   130: aastore
    //   131: dup
    //   132: iconst_5
    //   133: ldc -73
    //   135: aastore
    //   136: dup
    //   137: bipush 6
    //   139: ldc -72
    //   141: aastore
    //   142: dup
    //   143: bipush 7
    //   145: ldc -71
    //   147: aastore
    //   148: ldc -69
    //   150: invokestatic 154    java/lang/Class:forName (Ljava/lang/String;)Ljava/lang/Class;
    //   153: dup
    //   154: astore_1
    //   155: invokevirtual 164    java/lang/Class:getDeclaredMethods  ()[Ljava/lang/reflect/Method;
    //   158: invokestatic 170    org/springframework/cglib/core/ReflectUtils:findMethods ([Ljava/lang/String;[Ljava/lang/reflect/Method;)[Ljava/lang/reflect/Method;
    //   161: dup
    //   162: iconst_0
    //   163: aaload
    //   164: putstatic 80    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$equals$2$Method  Ljava/lang/reflect/Method;
    //   167: aload_1
    //   168: aload_0
    //   169: ldc -76
    //   171: ldc -77
    //   173: ldc -68
    //   175: invokestatic 177    org/springframework/cglib/proxy/MethodProxy:create  (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/springframework/cglib/proxy/MethodProxy;
    //   178: putstatic 82    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$equals$2$Proxy   Lorg/springframework/cglib/proxy/MethodProxy;
    //   181: dup
    //   182: iconst_1
    //   183: aaload
    //   184: putstatic 96    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$toString$3$Method    Ljava/lang/reflect/Method;
    //   187: aload_1
    //   188: aload_0
    //   189: ldc -98
    //   191: ldc -75
    //   193: ldc -67
    //   195: invokestatic 177    org/springframework/cglib/proxy/MethodProxy:create  (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/springframework/cglib/proxy/MethodProxy;
    //   198: putstatic 98    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$toString$3$Proxy Lorg/springframework/cglib/proxy/MethodProxy;
    //   201: dup
    //   202: iconst_2
    //   203: aaload
    //   204: putstatic 107    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$hashCode$4$Method    Ljava/lang/reflect/Method;
    //   207: aload_1
    //   208: aload_0
    //   209: ldc -73
    //   211: ldc -74
    //   213: ldc -66
    //   215: invokestatic 177    org/springframework/cglib/proxy/MethodProxy:create  (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/springframework/cglib/proxy/MethodProxy;
    //   218: putstatic 109    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$hashCode$4$Proxy Lorg/springframework/cglib/proxy/MethodProxy;
    //   221: dup
    //   222: iconst_3
    //   223: aaload
    //   224: putstatic 125    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$clone$5$Method   Ljava/lang/reflect/Method;
    //   227: aload_1
    //   228: aload_0
    //   229: ldc -71
    //   231: ldc -72
    //   233: ldc -65
    //   235: invokestatic 177    org/springframework/cglib/proxy/MethodProxy:create  (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/springframework/cglib/proxy/MethodProxy;
    //   238: putstatic 127    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$clone$5$Proxy    Lorg/springframework/cglib/proxy/MethodProxy;
    //   241: pop
    //   242: return
    //   243: athrow
  }

  final String CGLIB$sayHello$0(String paramString)
  {
    return super.sayHello(paramString);
  }

  public final String sayHello(String paramString)
  {
    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
    if (tmp4_1 == null)
    {
      tmp4_1;
      CGLIB$BIND_CALLBACKS(this);
    }
    MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
    if (tmp17_14 != null) {
      return (String)tmp17_14.intercept(this, CGLIB$sayHello$0$Method, new Object[] { paramString }, CGLIB$sayHello$0$Proxy);
    }
    return super.sayHello(paramString);
  }

  final String CGLIB$sayGoodBye$1()
  {
    return super.sayGoodBye();
  }

  public final String sayGoodBye()
  {
    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
    if (tmp4_1 == null)
    {
      tmp4_1;
      CGLIB$BIND_CALLBACKS(this);
    }
    MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
    if (tmp17_14 != null) {
      return (String)tmp17_14.intercept(this, CGLIB$sayGoodBye$1$Method, CGLIB$emptyArgs, CGLIB$sayGoodBye$1$Proxy);
    }
    return super.sayGoodBye();
  }

  final boolean CGLIB$equals$2(Object paramObject)
  {
    return super.equals(paramObject);
  }

  public final boolean equals(Object paramObject)
  {
    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
    if (tmp4_1 == null)
    {
      tmp4_1;
      CGLIB$BIND_CALLBACKS(this);
    }
    MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
    if (tmp17_14 != null)
    {
      Object tmp41_36 = tmp17_14.intercept(this, CGLIB$equals$2$Method, new Object[] { paramObject }, CGLIB$equals$2$Proxy);
      tmp41_36;
      return tmp41_36 == null ? false : ((Boolean)tmp41_36).booleanValue();
    }
    return super.equals(paramObject);
  }

  final String CGLIB$toString$3()
  {
    return super.toString();
  }

  public final String toString()
  {
    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
    if (tmp4_1 == null)
    {
      tmp4_1;
      CGLIB$BIND_CALLBACKS(this);
    }
    MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
    if (tmp17_14 != null) {
      return (String)tmp17_14.intercept(this, CGLIB$toString$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy);
    }
    return super.toString();
  }

  final int CGLIB$hashCode$4()
  {
    return super.hashCode();
  }

  public final int hashCode()
  {
    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
    if (tmp4_1 == null)
    {
      tmp4_1;
      CGLIB$BIND_CALLBACKS(this);
    }
    MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
    if (tmp17_14 != null)
    {
      Object tmp36_31 = tmp17_14.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);
      tmp36_31;
      return tmp36_31 == null ? 0 : ((Number)tmp36_31).intValue();
    }
    return super.hashCode();
  }

  final Object CGLIB$clone$5()
    throws CloneNotSupportedException
  {
    return super.clone();
  }

  protected final Object clone()
    throws CloneNotSupportedException
  {
    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
    if (tmp4_1 == null)
    {
      tmp4_1;
      CGLIB$BIND_CALLBACKS(this);
    }
    MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
    if (tmp17_14 != null) {
      return tmp17_14.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy);
    }
    return super.clone();
  }

  /* Error */
  public static MethodProxy CGLIB$findMethodProxy(org.springframework.cglib.core.Signature arg0)
  {
    // Byte code:
    //   0: aload_0
    //   1: invokevirtual 130    java/lang/Object:toString   ()Ljava/lang/String;
    //   4: dup
    //   5: invokevirtual 131    java/lang/Object:hashCode   ()I
    //   8: lookupswitch    default:+132->140, -1816210712:+60->68, -508378822:+72->80, 1577955665:+84->92, 1826985398:+96->104, 1913648695:+108->116, 1984935277:+120->128
    //   68: ldc -123
    //   70: invokevirtual 134    java/lang/Object:equals (Ljava/lang/Object;)Z
    //   73: ifeq +68 -> 141
    //   76: getstatic 50    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$sayHello$0$Proxy Lorg/springframework/cglib/proxy/MethodProxy;
    //   79: areturn
    //   80: ldc -120
    //   82: invokevirtual 134    java/lang/Object:equals (Ljava/lang/Object;)Z
    //   85: ifeq +56 -> 141
    //   88: getstatic 127    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$clone$5$Proxy    Lorg/springframework/cglib/proxy/MethodProxy;
    //   91: areturn
    //   92: ldc -118
    //   94: invokevirtual 134    java/lang/Object:equals (Ljava/lang/Object;)Z
    //   97: ifeq +44 -> 141
    //   100: getstatic 71    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$sayGoodBye$1$Proxy   Lorg/springframework/cglib/proxy/MethodProxy;
    //   103: areturn
    //   104: ldc -116
    //   106: invokevirtual 134    java/lang/Object:equals (Ljava/lang/Object;)Z
    //   109: ifeq +32 -> 141
    //   112: getstatic 82    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$equals$2$Proxy   Lorg/springframework/cglib/proxy/MethodProxy;
    //   115: areturn
    //   116: ldc -114
    //   118: invokevirtual 134    java/lang/Object:equals (Ljava/lang/Object;)Z
    //   121: ifeq +20 -> 141
    //   124: getstatic 98    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$toString$3$Proxy Lorg/springframework/cglib/proxy/MethodProxy;
    //   127: areturn
    //   128: ldc -112
    //   130: invokevirtual 134    java/lang/Object:equals (Ljava/lang/Object;)Z
    //   133: ifeq +8 -> 141
    //   136: getstatic 109    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$hashCode$4$Proxy Lorg/springframework/cglib/proxy/MethodProxy;
    //   139: areturn
    //   140: pop
    //   141: aconst_null
    //   142: areturn
  }

  public RealSubject$$EnhancerByCGLIB$$6a387257()
  {
    CGLIB$BIND_CALLBACKS(this);
  }

  public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] paramArrayOfCallback)
  {
    CGLIB$THREAD_CALLBACKS.set(paramArrayOfCallback);
  }

  public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] paramArrayOfCallback)
  {
    CGLIB$STATIC_CALLBACKS = paramArrayOfCallback;
  }

  private static final void CGLIB$BIND_CALLBACKS(Object paramObject)
  {
    6a387257 local6a387257 = (6a387257)paramObject;
    if (!local6a387257.CGLIB$BOUND)
    {
      local6a387257.CGLIB$BOUND = true;
      Object tmp23_20 = CGLIB$THREAD_CALLBACKS.get();
      if (tmp23_20 == null)
      {
        tmp23_20;
        CGLIB$STATIC_CALLBACKS;
      }
      local6a387257.CGLIB$CALLBACK_0 = (tmp31_28 == null ? tmp31_28 : (MethodInterceptor)((Callback[])tmp23_20)[0]);
    }
  }

  public Object newInstance(Callback[] paramArrayOfCallback)
  {
    CGLIB$SET_THREAD_CALLBACKS(paramArrayOfCallback);
    CGLIB$SET_THREAD_CALLBACKS(null);
    return new 6a387257();
  }

  public Object newInstance(Callback paramCallback)
  {
    CGLIB$SET_THREAD_CALLBACKS(new Callback[] { paramCallback });
    CGLIB$SET_THREAD_CALLBACKS(null);
    return new 6a387257();
  }

  /* Error */
  public Object newInstance(Class[] arg1, Object[] arg2, Callback[] arg3)
  {
    // Byte code:
    //   0: aload_3
    //   1: invokestatic 210    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$SET_THREAD_CALLBACKS   ([Lorg/springframework/cglib/proxy/Callback;)V
    //   4: new 2    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257
    //   7: dup
    //   8: aload_1
    //   9: dup
    //   10: arraylength
    //   11: tableswitch    default:+24->35, 0:+17->28
    //   28: pop
    //   29: invokespecial 211    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:<init>    ()V
    //   32: goto +17 -> 49
    //   35: goto +3 -> 38
    //   38: pop
    //   39: new 217    java/lang/IllegalArgumentException
    //   42: dup
    //   43: ldc -37
    //   45: invokespecial 222    java/lang/IllegalArgumentException:<init>   (Ljava/lang/String;)V
    //   48: athrow
    //   49: aconst_null
    //   50: invokestatic 210    com/example/ford/proxy/RealSubject$$EnhancerByCGLIB$$6a387257:CGLIB$SET_THREAD_CALLBACKS   ([Lorg/springframework/cglib/proxy/Callback;)V
    //   53: areturn
  }

  public Callback getCallback(int paramInt)
  {
    CGLIB$BIND_CALLBACKS(this);
    switch (paramInt)
    {
    case 0: 
      break;
    }
    return null;
  }

  public void setCallback(int paramInt, Callback paramCallback)
  {
    switch (paramInt)
    {
    case 0: 
      this.CGLIB$CALLBACK_0 = ((MethodInterceptor)paramCallback);
      break;
    }
  }

  public Callback[] getCallbacks()
  {
    CGLIB$BIND_CALLBACKS(this);
    return new Callback[] { this.CGLIB$CALLBACK_0 };
  }

  public void setCallbacks(Callback[] paramArrayOfCallback)
  {
    this.CGLIB$CALLBACK_0 = ((MethodInterceptor)paramArrayOfCallback[0]);
  }

  static {}
}

每个被代理的方法都对应一个MethodProxy对象,methodProxy.invokeSuper方法最终调用委托类的add方法

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();
    }
}

单看invokeSuper方法的实现,似乎看不出委托类add方法调用,在MethodProxy实现中,通过FastClassInfo维护了委托类和代理类的FastClass。

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

以sayHello方法的methodProxy为例,f1指向委托类对象,f2指向代理类对象,i1和i2分别是方法sayHello和CGLIB$sayHello$0在对象中索引位置。

FastClass实现机制

FastClass其实就是对Class对象进行特殊处理,提出下标概念index,通过索引保存方法的引用信息,将原先的反射调用,转化为方法的直接调用,从而体现所谓的fast,下面通过一个例子了解一下FastClass的实现机制。

1、定义原类

class Test {  
    public void f(){
        System.out.println("f method");
    }

    public void g(){
        System.out.println("g method");
    }
}

2、定义Fast类

class FastTest {  
    public int getIndex(String signature){
        switch(signature.hashCode()){
        case 3078479:
            return 1;
        case 3108270:
            return 2;
        }
        return -1;
    }

    public Object invoke(int index, Object o, Object[] ol){
        Test t = (Test) o;
        switch(index){
        case 1:
            t.f();
            return null;
        case 2:
            t.g();
            return null;
        }
        return null;
    }
}

在FastTest中有两个方法,getIndex中对Test类的每个方法根据hash建立索引,invoke根据指定的索引,直接调用目标方法,避免了反射调用。所以当调用methodProxy.invokeSuper方法时,实际上是调用代理类的CGLIB$sayHello$0方法,CGLIB$sayHello$0直接调用了委托类的sayHello方法