JDK动态代理和CGLib代理实现分析


1、JDK动态代理


JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。
其中 InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一 起。
而Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例。

InvocationHandler接口: 

public interface InvocationHandler { 
  public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; 
} 
Object proxy:指被代理的对象
Method method:要调用的方法
Object[] args:方法调用时所需要的参数

可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。 

Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException 
参数说明: 
ClassLoader loader:类加载器 
Class<?>[] interfaces:得到全部的接口 
InvocationHandler h:得到InvocationHandler接口的子类实例

对于以下类

public interface Subject {
  void doSomething();
}

public class RealSubject implements Subject {
  public void doSomething() {
    System.out.println("doSomething");
  }
}

实现JDK动态代理类

public class JDKProxy implements InvocationHandler {

  private Object proxied;

    /** 
     * 绑定委托对象并返回一个代理类 
     * 只能绑定接口(cglib弥补了这一缺陷)
     * @param target,被代理对象
     * @return 
     */  
    public Object bind(Object proxied) {  
        this.proxied = proxied; 
        return Proxy.newProxyInstance(proxied.getClass().getClassLoader(), 
                      proxied.getClass().getInterfaces(), this);     
    } 

  public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable {
    System.out.println("*** proxy *** "  + proxy.getClass());
    System.out.println("*** method ** *" + method);
    System.out.println("*** args *** "   + args);
    // 可以在这里做一些处理,如查看方法名,查看方法签名的其他方面,甚至可以搜索特定的参数值
    if(method.getName().equals("doSomething"))
      System.out.println("Proxy detected the doSomething method.");
    // 将请求转发给被代理对象,并传入必须的参数
    method.invoke(proxied, args);
    return null;
  }

}

调用方式

// 创建被代理的真实对象
RealSubject real = new RealSubject();
// 创建JDK动态代理类
JDKProxy proxy = new JDKProxy();
// 绑定真实对象,生成真实代理类
Subject subject = (Subject) proxy.bind(real);
subject.doSomething();

JDKProxy动态代理RealSubject生成的真实代理类com.sun.proxy.$Proxy0;
整个过程相当如

JDKProxy proxy = new JDKProxy();
$Proxy0 subject = com.sun.proxy.$Proxy0(proxy);
subject.doSomething();
package com.sun.proxy;

import com.charles.Subject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

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

  public $Proxy0(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 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 void doSomething() {
    try {
      this.h.invoke(this, m3, null);
      return;
    } 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") });
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m3 = Class.forName("com.charles.Subject").getMethod("doSomething", 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());
    }
  }
  
}

2、CGLib代理

CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

该类实现了创建子类的方法与代理的方法。getProxy(SuperClass.class)方法通过入参即父类的字节码,通过扩展父类的class来创建代理对象。intercept()方法拦截所有目标类方法的调用,obj表示目标类的实例,method为目标类方法的反射对象,args为方法的动态入参,proxy为代理类实例。proxy.invokeSuper(obj, args)通过代理类调用父类中的方法。

public class CGlibProxy implements MethodInterceptor {

    private Enhancer enhancer = new Enhancer();

    @SuppressWarnings("rawtypes")
    public Object getProxy(Class clazz) {
        // 设置需要创建子类的类
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        // 通过字节码技术动态创建子类实例
        return enhancer.create();
    }
    
  public Object intercept(Object obj, Method method, Object[] args,
      MethodProxy proxy) throws Throwable {
        // 通过代理类调用父类中的方法
        Object result = proxy.invokeSuper(obj, args);
        return null;
  }

}

调用

CGlibProxy proxy = new CGlibProxy();
Subject subject = (Subject)proxy.getProxy(RealSubject.class);
subject.doSomething();

CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。

通过字节码生成的代理类为RealSubject$$EnhancerByCGLIB$$ab318164
然后就调用其doSomething()方法,其方法定义为

public final void doSomething() {
  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.doSomething();
}

生成的完整的类为

package com.charles;

import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
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 RealSubject$$EnhancerByCGLIB$$ab318164 extends RealSubject implements Factory {

  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$doSomething$0$Method;
  private static final MethodProxy CGLIB$doSomething$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 localClass1 = Class.forName("com.charles.RealSubject$$EnhancerByCGLIB$$ab318164");
    Class localClass2;
    Method[] tmp95_92 = ReflectUtils.findMethods(new String[] { "finalize", "()V", "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (localClass2 = Class.forName("java.lang.Object")).getDeclaredMethods());
    CGLIB$finalize$1$Method = tmp95_92[0];
    CGLIB$finalize$1$Proxy = MethodProxy.create(localClass2, localClass1, "()V", "finalize", "CGLIB$finalize$1");
    Method[] tmp115_95 = tmp95_92;
    CGLIB$equals$2$Method = tmp115_95[1];
    CGLIB$equals$2$Proxy = MethodProxy.create(localClass2, localClass1, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$2");
    Method[] tmp135_115 = tmp115_95;
    CGLIB$toString$3$Method = tmp135_115[2];
    CGLIB$toString$3$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/String;", "toString", "CGLIB$toString$3");
    Method[] tmp155_135 = tmp135_115;
    CGLIB$hashCode$4$Method = tmp155_135[3];
    CGLIB$hashCode$4$Proxy = MethodProxy.create(localClass2, localClass1, "()I", "hashCode", "CGLIB$hashCode$4");
    Method[] tmp175_155 = tmp155_135;
    CGLIB$clone$5$Method = tmp175_155[4];
    CGLIB$clone$5$Proxy = MethodProxy.create(localClass2, localClass1, "()Ljava/lang/Object;", "clone", "CGLIB$clone$5");
    tmp175_155;
    Method[] tmp223_220 = ReflectUtils.findMethods(new String[] { "doSomething", "()V" }, (localClass2 = Class.forName("com.charles.RealSubject")).getDeclaredMethods());
    CGLIB$doSomething$0$Method = tmp223_220[0];
    CGLIB$doSomething$0$Proxy = MethodProxy.create(localClass2, localClass1, "()V", "doSomething", "CGLIB$doSomething$0");
    tmp223_220;
    return;
  }

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

  public final void doSomething() {
    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.doSomething();
  }

  final void CGLIB$finalize$1() throws Throwable {
    super.finalize();
  }

  protected final void finalize()  throws Throwable {
    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.finalize();
  }

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

  public static MethodProxy CGLIB$findMethodProxy(Signature paramSignature) {
    String tmp4_1 = paramSignature.toString();
    switch (tmp4_1.hashCode()) {
    case -1574182249:
      if (tmp4_1.equals("finalize()V"))
        return CGLIB$finalize$1$Proxy;
      break;
    case -508378822:
    case 1826985398:
    case 1913648695:
    case 1984935277:
    case 2121560294:
    }
  }

  public RealSubject$$EnhancerByCGLIB$$ab318164() {
    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) {
    // Byte code:
    //   0: aload_0
    //   1: checkcast 2 com/charles/RealSubject$$EnhancerByCGLIB$$ab318164
    //   4: astore_1
    //   5: aload_1
    //   6: getfield 198  com/charles/RealSubject$$EnhancerByCGLIB$$ab318164:CGLIB$BOUND  Z
    //   9: ifne +43 -> 52
    //   12: aload_1
    //   13: iconst_1
    //   14: putfield 198 com/charles/RealSubject$$EnhancerByCGLIB$$ab318164:CGLIB$BOUND  Z
    //   17: getstatic 24 com/charles/RealSubject$$EnhancerByCGLIB$$ab318164:CGLIB$THREAD_CALLBACKS Ljava/lang/ThreadLocal;
    //   20: invokevirtual 201  java/lang/ThreadLocal:get ()Ljava/lang/Object;
    //   23: dup
    //   24: ifnonnull +15 -> 39
    //   27: pop
    //   28: getstatic 196  com/charles/RealSubject$$EnhancerByCGLIB$$ab318164:CGLIB$STATIC_CALLBACKS [Lnet/sf/cglib/proxy/Callback;
    //   31: dup
    //   32: ifnonnull +7 -> 39
    //   35: pop
    //   36: goto +16 -> 52
    //   39: checkcast 202  [Lnet/sf/cglib/proxy/Callback;
    //   42: aload_1
    //   43: swap
    //   44: iconst_0
    //   45: aaload
    //   46: checkcast 48 net/sf/cglib/proxy/MethodInterceptor
    //   49: putfield 36  com/charles/RealSubject$$EnhancerByCGLIB$$ab318164:CGLIB$CALLBACK_0 Lnet/sf/cglib/proxy/MethodInterceptor;
    //   52: return
  }

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

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

  public Object newInstance(Class[] paramArrayOfClass, Object[] paramArrayOfObject, Callback[] paramArrayOfCallback) {
    CGLIB$SET_THREAD_CALLBACKS(paramArrayOfCallback);
    Class[] tmp9_8 = paramArrayOfClass;
    switch (tmp9_8.length) {
    case 0:
      tmp9_8;
      break;
    default:
      new ab318164();
      throw new IllegalArgumentException("Constructor not found");
    }
    CGLIB$SET_THREAD_CALLBACKS(null);
  }

  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 {
    CGLIB$STATICHOOK1();
  }
  
}