Junhc

岂止于博客

Java动态代理机制详解

静态代理模式固然在访问无法访问的资源、增强现有接口业务功能方面有很大的优点,但是大量使用静态代理,会使我们系统内的类规模增大,并且不易维护。 而且由于Proxy和RealSubject的功能本质上是相同的,Proxy只是起到了中介的作用,这代理在系统中的存在,导致系统结构比较臃肿和松散。

为了解决这个问题,就有了动态创建Proxy的想法,在运行状态中,根据Subject和RealSubject,动态的创建一个Proxy,用完之后,就销毁。 这就可以避免Proxy角色的class在系统中的冗杂问题了。

public interface IFly {

    void fly();
}
public interface IRun {

    void run();
}
public class Person implements IRun, IFly {

    @Override
    public void fly() {
        System.out.println("Person.fly");
    }

    @Override
    public void run() {
        System.out.println("Person.run");
    }
}
public class ProxyUtils {

    public static void generateClassFile(Class clazz, String proxyName) {
        // 根据类信息和提供的代理类名称,生成字节码
        byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
        String paths = clazz.getResource(".").getPath();
        FileOutputStream out = null;
        try {
            // 写入硬盘中
            out = new FileOutputStream(paths + proxyName + ".class");
            out.write(classFile);
            out.flush();
        } catch (Exception e) {
        } finally {
            try {
                out.close();
            } catch (Exception e) {
            }
        }
    }

    public static void main(String[] args) {
        // 将在同级目录下生成 PersonProxy.class 文件
        // 用反编译工具打开如下
        ProxyUtils.generateClassFile(Person.class, "PersonProxy");
    }
}
JDK动态代理机制,接口

过程如下

  1. 获取 RealSubject 的接口列表;
  2. 确定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX
  3. 根据需要实现的接口信息,在代码中动态创建该Proxy类的字节码
  4. 将对应的字节码转换为对应的class对象
  5. 创建InvocationHandler 实例handler,用来处理Proxy所有方法调用
  6. Proxy的class对象以创建的handler对象为参数,实例化一个Proxy对象
// 生成class文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
Object o = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{IFly.class, IRun.class}, new InvocationHandler() {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(new Person(), args);
    }
});
IFly fly = (IFly) o;
fly.fly();
import com.junhc.common.proxy.IFly;
import com.junhc.common.proxy.IRun;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class PersonProxy
  extends Proxy
  implements IRun, IFly
{
  private static Method m1;
  private static Method m3;
  private static Method m4;
  private static Method m0;
  private static Method m2;

  public PersonProxy(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 void run()
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final void fly()
  {
    try
    {
      this.h.invoke(this, m4, null);
      return;
    }
    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);
    }
  }

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

  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("com.junhc.common.proxy.IRun").getMethod("run", new Class[0]);
      m4 = Class.forName("com.junhc.common.proxy.IFly").getMethod("fly", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}
  • 继承 java.lang.reflect.Proxy,实现了 IFly、IRun 接口
  • 类中所有的方法都是 final
  • 所有方法的实现都统一使用 InvocationHandler 的 invoke 方法
CGLIB 动态代理机制,类继承

过程如下

  1. 查找A上的所有非final的public类型的方法定义
  2. 将这些方法的定义转换成字节码
  3. 将组成的字节码转换成相应的代理的class对象
  4. 实现 MethodInterceptor接口,用来处理对代理类上所有方法的请求(这个接口和JDK动态代理InvocationHandler的功能和角色是一样的)
String path = Person.class.getResource(".").getPath();
// 生成class文件
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, path);
Enhancer enhancer = new Enhancer();
// 设置要创建动态代理的类
enhancer.setSuperclass(Person.class);
// 设置回调,对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实行intercept()方法进行拦截
enhancer.setCallback(new MethodInterceptor() {
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        return proxy.invokeSuper(o, args);
    }
});
Object o = enhancer.create();
IFly fly = (IFly) o;
fly.fly();
package com.junhc.common.proxy;

import java.lang.reflect.Method;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class Person$$EnhancerByCGLIB$$dcfb2f4d
  extends Person
  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$run$0$Method;
  private static final MethodProxy CGLIB$run$0$Proxy;
  private static final Object[] CGLIB$emptyArgs;
  private static final Method CGLIB$fly$1$Method;
  private static final MethodProxy CGLIB$fly$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/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$THREAD_CALLBACKS	Ljava/lang/ThreadLocal;
    //   10: iconst_0
    //   11: anewarray 76	java/lang/Object
    //   14: putstatic 47	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$emptyArgs	[Ljava/lang/Object;
    //   17: ldc -109
    //   19: invokestatic 153	java/lang/Class:forName	(Ljava/lang/String;)Ljava/lang/Class;
    //   22: astore_0
    //   23: iconst_4
    //   24: anewarray 97	java/lang/String
    //   27: dup
    //   28: iconst_0
    //   29: ldc -102
    //   31: aastore
    //   32: dup
    //   33: iconst_1
    //   34: ldc -101
    //   36: aastore
    //   37: dup
    //   38: iconst_2
    //   39: ldc -100
    //   41: aastore
    //   42: dup
    //   43: iconst_3
    //   44: ldc -101
    //   46: aastore
    //   47: ldc -98
    //   49: invokestatic 153	java/lang/Class:forName	(Ljava/lang/String;)Ljava/lang/Class;
    //   52: dup
    //   53: astore_1
    //   54: invokevirtual 162	java/lang/Class:getDeclaredMethods	()[Ljava/lang/reflect/Method;
    //   57: invokestatic 168	net/sf/cglib/core/ReflectUtils:findMethods	([Ljava/lang/String;[Ljava/lang/reflect/Method;)[Ljava/lang/reflect/Method;
    //   60: dup
    //   61: iconst_0
    //   62: aaload
    //   63: putstatic 45	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$run$0$Method	Ljava/lang/reflect/Method;
    //   66: aload_1
    //   67: aload_0
    //   68: ldc -101
    //   70: ldc -102
    //   72: ldc -87
    //   74: invokestatic 175	net/sf/cglib/proxy/MethodProxy:create	(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lnet/sf/cglib/proxy/MethodProxy;
    //   77: putstatic 49	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$run$0$Proxy	Lnet/sf/cglib/proxy/MethodProxy;
    //   80: dup
    //   81: iconst_1
    //   82: aaload
    //   83: putstatic 63	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$fly$1$Method	Ljava/lang/reflect/Method;
    //   86: aload_1
    //   87: aload_0
    //   88: ldc -101
    //   90: ldc -100
    //   92: ldc -80
    //   94: invokestatic 175	net/sf/cglib/proxy/MethodProxy:create	(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lnet/sf/cglib/proxy/MethodProxy;
    //   97: putstatic 65	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$fly$1$Proxy	Lnet/sf/cglib/proxy/MethodProxy;
    //   100: pop
    //   101: bipush 8
    //   103: anewarray 97	java/lang/String
    //   106: dup
    //   107: iconst_0
    //   108: ldc -79
    //   110: aastore
    //   111: dup
    //   112: iconst_1
    //   113: ldc -78
    //   115: aastore
    //   116: dup
    //   117: iconst_2
    //   118: ldc -77
    //   120: aastore
    //   121: dup
    //   122: iconst_3
    //   123: ldc -76
    //   125: aastore
    //   126: dup
    //   127: iconst_4
    //   128: ldc -75
    //   130: aastore
    //   131: dup
    //   132: iconst_5
    //   133: ldc -74
    //   135: aastore
    //   136: dup
    //   137: bipush 6
    //   139: ldc -73
    //   141: aastore
    //   142: dup
    //   143: bipush 7
    //   145: ldc -72
    //   147: aastore
    //   148: ldc -70
    //   150: invokestatic 153	java/lang/Class:forName	(Ljava/lang/String;)Ljava/lang/Class;
    //   153: dup
    //   154: astore_1
    //   155: invokevirtual 162	java/lang/Class:getDeclaredMethods	()[Ljava/lang/reflect/Method;
    //   158: invokestatic 168	net/sf/cglib/core/ReflectUtils:findMethods	([Ljava/lang/String;[Ljava/lang/reflect/Method;)[Ljava/lang/reflect/Method;
    //   161: dup
    //   162: iconst_0
    //   163: aaload
    //   164: putstatic 74	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$equals$2$Method	Ljava/lang/reflect/Method;
    //   167: aload_1
    //   168: aload_0
    //   169: ldc -78
    //   171: ldc -79
    //   173: ldc -69
    //   175: invokestatic 175	net/sf/cglib/proxy/MethodProxy:create	(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lnet/sf/cglib/proxy/MethodProxy;
    //   178: putstatic 78	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$equals$2$Proxy	Lnet/sf/cglib/proxy/MethodProxy;
    //   181: dup
    //   182: iconst_1
    //   183: aaload
    //   184: putstatic 93	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$toString$3$Method	Ljava/lang/reflect/Method;
    //   187: aload_1
    //   188: aload_0
    //   189: ldc -76
    //   191: ldc -77
    //   193: ldc -68
    //   195: invokestatic 175	net/sf/cglib/proxy/MethodProxy:create	(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lnet/sf/cglib/proxy/MethodProxy;
    //   198: putstatic 95	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$toString$3$Proxy	Lnet/sf/cglib/proxy/MethodProxy;
    //   201: dup
    //   202: iconst_2
    //   203: aaload
    //   204: putstatic 106	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$hashCode$4$Method	Ljava/lang/reflect/Method;
    //   207: aload_1
    //   208: aload_0
    //   209: ldc -74
    //   211: ldc -75
    //   213: ldc -67
    //   215: invokestatic 175	net/sf/cglib/proxy/MethodProxy:create	(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lnet/sf/cglib/proxy/MethodProxy;
    //   218: putstatic 108	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$hashCode$4$Proxy	Lnet/sf/cglib/proxy/MethodProxy;
    //   221: dup
    //   222: iconst_3
    //   223: aaload
    //   224: putstatic 124	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$clone$5$Method	Ljava/lang/reflect/Method;
    //   227: aload_1
    //   228: aload_0
    //   229: ldc -72
    //   231: ldc -73
    //   233: ldc -66
    //   235: invokestatic 175	net/sf/cglib/proxy/MethodProxy:create	(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lnet/sf/cglib/proxy/MethodProxy;
    //   238: putstatic 126	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$clone$5$Proxy	Lnet/sf/cglib/proxy/MethodProxy;
    //   241: pop
    //   242: return
    //   243: athrow
  }

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

  public final void run()
  {
    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
    if (tmp4_1 == null)
    {
      tmp4_1;
      CGLIB$BIND_CALLBACKS(this);
    }
    if (this.CGLIB$CALLBACK_0 != null) {
      return;
    }
    super.run();
  }

  final void CGLIB$fly$1()
  {
    super.fly();
  }

  public final void fly()
  {
    MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
    if (tmp4_1 == null)
    {
      tmp4_1;
      CGLIB$BIND_CALLBACKS(this);
    }
    if (this.CGLIB$CALLBACK_0 != null) {
      return;
    }
    super.fly();
  }

  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(net.sf.cglib.core.Signature arg0)
  {
    // Byte code:
    //   0: aload_0
    //   1: invokevirtual 129	java/lang/Object:toString	()Ljava/lang/String;
    //   4: dup
    //   5: invokevirtual 130	java/lang/Object:hashCode	()I
    //   8: lookupswitch	default:+132->140, -1271409118:+60->68, -919875318:+72->80, -508378822:+84->92, 1826985398:+96->104, 1913648695:+108->116, 1984935277:+120->128
    //   68: ldc -124
    //   70: invokevirtual 133	java/lang/Object:equals	(Ljava/lang/Object;)Z
    //   73: ifeq +68 -> 141
    //   76: getstatic 65	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$fly$1$Proxy	Lnet/sf/cglib/proxy/MethodProxy;
    //   79: areturn
    //   80: ldc -121
    //   82: invokevirtual 133	java/lang/Object:equals	(Ljava/lang/Object;)Z
    //   85: ifeq +56 -> 141
    //   88: getstatic 49	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$run$0$Proxy	Lnet/sf/cglib/proxy/MethodProxy;
    //   91: areturn
    //   92: ldc -119
    //   94: invokevirtual 133	java/lang/Object:equals	(Ljava/lang/Object;)Z
    //   97: ifeq +44 -> 141
    //   100: getstatic 126	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$clone$5$Proxy	Lnet/sf/cglib/proxy/MethodProxy;
    //   103: areturn
    //   104: ldc -117
    //   106: invokevirtual 133	java/lang/Object:equals	(Ljava/lang/Object;)Z
    //   109: ifeq +32 -> 141
    //   112: getstatic 78	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$equals$2$Proxy	Lnet/sf/cglib/proxy/MethodProxy;
    //   115: areturn
    //   116: ldc -115
    //   118: invokevirtual 133	java/lang/Object:equals	(Ljava/lang/Object;)Z
    //   121: ifeq +20 -> 141
    //   124: getstatic 95	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$toString$3$Proxy	Lnet/sf/cglib/proxy/MethodProxy;
    //   127: areturn
    //   128: ldc -113
    //   130: invokevirtual 133	java/lang/Object:equals	(Ljava/lang/Object;)Z
    //   133: ifeq +8 -> 141
    //   136: getstatic 108	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$hashCode$4$Proxy	Lnet/sf/cglib/proxy/MethodProxy;
    //   139: areturn
    //   140: pop
    //   141: aconst_null
    //   142: areturn
  }

  public Person$$EnhancerByCGLIB$$dcfb2f4d()
  {
    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)
  {
    dcfb2f4d localdcfb2f4d = (dcfb2f4d)paramObject;
    if (!localdcfb2f4d.CGLIB$BOUND)
    {
      localdcfb2f4d.CGLIB$BOUND = true;
      Object tmp23_20 = CGLIB$THREAD_CALLBACKS.get();
      if (tmp23_20 == null)
      {
        tmp23_20;
        CGLIB$STATIC_CALLBACKS;
      }
      localdcfb2f4d.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 dcfb2f4d();
  }

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

  /* Error */
  public Object newInstance(Class[] arg1, Object[] arg2, Callback[] arg3)
  {
    // Byte code:
    //   0: aload_3
    //   1: invokestatic 209	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$SET_THREAD_CALLBACKS	([Lnet/sf/cglib/proxy/Callback;)V
    //   4: new 2	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d
    //   7: dup
    //   8: aload_1
    //   9: dup
    //   10: arraylength
    //   11: tableswitch	default:+24->35, 0:+17->28
    //   28: pop
    //   29: invokespecial 210	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:<init>	()V
    //   32: goto +17 -> 49
    //   35: goto +3 -> 38
    //   38: pop
    //   39: new 216	java/lang/IllegalArgumentException
    //   42: dup
    //   43: ldc -38
    //   45: invokespecial 221	java/lang/IllegalArgumentException:<init>	(Ljava/lang/String;)V
    //   48: athrow
    //   49: aconst_null
    //   50: invokestatic 209	com/junhc/common/proxy/Person$$EnhancerByCGLIB$$dcfb2f4d:CGLIB$SET_THREAD_CALLBACKS	([Lnet/sf/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 {}
}
  • 代理类Person\(EnhancerByCGLIB\)dcfb2f4d继承委托类Person,且委托类的final方法不能被代理
  • 代理类为每个委托方法都生成两个方法,一个是重写方法、一个是CGLIB$run$0方法,该方法直接调用委托类的run方法
  • 当执行代理对象的run方法时,会先判断是否存在实现了MethodInterceptor接口的对象cglib$CALLBACK_0,如果存在,则调用MethodInterceptor对象的intercept方法:
public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) {
    System.out.println("Before:" + method);  
    Object object = proxy.invokeSuper(obj, arg);
    System.out.println("After:" + method);
    return object;
}
  • 参数分别为:
  • 1、代理对象;
  • 2、委托类方法;
  • 3、方法参数;
  • 4、代理方法的MethodProxy对象。

每个被代理的方法都对应一个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;
}

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

FastClass实现机制

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

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

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

2、定义Fast类

```vim
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$run$0方法,CGLIB$run$0直接调用了委托类的run方法。

JDK和CGLIB动态代理实现的区别
  1. JDK动态代理生成的代理类和委托类实现了相同的接口
  2. CGLIB动态代理中生成的字节码更加复杂,生成的代理类是委托类的子类,且不能处理被final关键字修饰的方法
  3. JDK采用反射机制调用委托类的方法,CGLIB采用类似索引的方式直接调用委托类方法
使用 HSDB JVM运行时数据可视化工具获取动态生成的class文件
  1. java -cp ‘%JAVA_HOME%/lib/sa-jdi.jar’ sun.jvm.hotspot.HSDB
  2. 点击 File 菜单, Attach to HotSpot process, 输入Java程序的进程号PID
  3. 点击 Tools 菜单, Class Browser, 输入包名
  4. 点击 Create .class File
参考资料

Java动态代理机制详解 Cglib动态代理原理分析