CgLib动态代理的实现原理

首先使用JD-GUI或者jad等工具对生成的代理类进行反编译

代理类

代理类由几部分组成

  • 父类的方法
  • 类似CGLIB$sayHi$0$Proxy的方法
  • newInstance方法
  • get/setCallback方法
package com.daniel.dynamicproxy.cglibproxy;

import java.lang.reflect.Method;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.cglib.core.Signature;
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 TargetClass$$EnhancerByCGLIB$$e1d08fdc extends TargetClass 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;
  
  // 为目标对象生成Method和MethodProxy
  
  // 可以看到,这里只对sayHi生成了代理,而没有对sayHello生成代理,因为final修饰的方法是不允许被继承的
  private static final Method CGLIB$sayHi$0$Method;
  
  private static final MethodProxy CGLIB$sayHi$0$Proxy;
  
  private static final Object[] CGLIB$emptyArgs;
  
  // equals
  private static final Method CGLIB$equals$1$Method;
  
  private static final MethodProxy CGLIB$equals$1$Proxy;
  
  // toString
  private static final Method CGLIB$toString$2$Method;
  
  private static final MethodProxy CGLIB$toString$2$Proxy;
  
  // hashCode
  private static final Method CGLIB$hashCode$3$Method;
  
  private static final MethodProxy CGLIB$hashCode$3$Proxy;
  
  // clone
  private static final Method CGLIB$clone$4$Method;
  
  private static final MethodProxy CGLIB$clone$4$Proxy;
  
  // 静态代码块,调用了下面的静态方法
  static {
    CGLIB$STATICHOOK1();
  }
  
  // 无参构造器
  public TargetClass$$EnhancerByCGLIB$$e1d08fdc() {
    CGLIB$BIND_CALLBACKS(this);
  }
  
  static void CGLIB$STATICHOOK1() {
    CGLIB$THREAD_CALLBACKS = new ThreadLocal();
    CGLIB$emptyArgs = new Object[0];
    Class<?> clazz1 = Class.forName("com.daniel.dynamicproxy.cglibproxy.TargetClass$$EnhancerByCGLIB$$e1d08fdc");
    Class<?> clazz2;
    
    ...
    
    CGLIB$sayHi$0$Method = ReflectUtils.findMethods(new String[] { "sayHi", "()V" }, (clazz2 = Class.forName("com.daniel.dynamicproxy.cglibproxy.TargetClass")).getDeclaredMethods())[0];
    CGLIB$sayHi$0$Proxy = MethodProxy.create(clazz2, clazz1, "()V", "sayHi", "CGLIB$sayHi$0");
    ReflectUtils.findMethods(new String[] { "sayHi", "()V" }, (clazz2 = Class.forName("com.daniel.dynamicproxy.cglibproxy.TargetClass")).getDeclaredMethods());
  }
  
  // 调用目标类的方法
  final void CGLIB$sayHi$0() {
    super.sayHi();
  }
  
  public final void sayHi() {
    if (this.CGLIB$CALLBACK_0 == null)
      CGLIB$BIND_CALLBACKS(this); 
    if (this.CGLIB$CALLBACK_0 != null)
      return; 
    super.sayHi();
  }
  
  // ...省略
    
  public static MethodProxy CGLIB$findMethodProxy(Signature paramSignature) {
    // Byte code:
    //   0: aload_0
    //   1: invokevirtual toString : ()Ljava/lang/String;
    //   4: dup
    //   5: invokevirtual hashCode : ()I
    //   8: lookupswitch default -> 120, -2012941911 -> 60, -508378822 -> 72, 1826985398 -> 84, 1913648695 -> 96, 1984935277 -> 108
    //   60: ldc 'sayHi()V'
    //   62: invokevirtual equals : (Ljava/lang/Object;)Z
    //   65: ifeq -> 121
    //   68: getstatic com/daniel/dynamicproxy/cglibproxy/TargetClass$$EnhancerByCGLIB$$e1d08fdc.CGLIB$sayHi$0$Proxy : Lorg/springframework/cglib/proxy/MethodProxy;
    //   71: areturn
    //   72: ldc 'clone()Ljava/lang/Object;'
    //   74: invokevirtual equals : (Ljava/lang/Object;)Z
    //   77: ifeq -> 121
    //   80: getstatic com/daniel/dynamicproxy/cglibproxy/TargetClass$$EnhancerByCGLIB$$e1d08fdc.CGLIB$clone$4$Proxy : Lorg/springframework/cglib/proxy/MethodProxy;
    //   83: areturn
    //   84: ldc 'equals(Ljava/lang/Object;)Z'
    //   86: invokevirtual equals : (Ljava/lang/Object;)Z
    //   89: ifeq -> 121
    //   92: getstatic com/daniel/dynamicproxy/cglibproxy/TargetClass$$EnhancerByCGLIB$$e1d08fdc.CGLIB$equals$1$Proxy : Lorg/springframework/cglib/proxy/MethodProxy;
    //   95: areturn
    //   96: ldc 'toString()Ljava/lang/String;'
    //   98: invokevirtual equals : (Ljava/lang/Object;)Z
    //   101: ifeq -> 121
    //   104: getstatic com/daniel/dynamicproxy/cglibproxy/TargetClass$$EnhancerByCGLIB$$e1d08fdc.CGLIB$toString$2$Proxy : Lorg/springframework/cglib/proxy/MethodProxy;
    //   107: areturn
    //   108: ldc 'hashCode()I'
    //   110: invokevirtual equals : (Ljava/lang/Object;)Z
    //   113: ifeq -> 121
    //   116: getstatic com/daniel/dynamicproxy/cglibproxy/TargetClass$$EnhancerByCGLIB$$e1d08fdc.CGLIB$hashCode$3$Proxy : Lorg/springframework/cglib/proxy/MethodProxy;
    //   119: areturn
    //   120: pop
    //   121: aconst_null
    //   122: areturn
  }
  
  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) {
    TargetClass$$EnhancerByCGLIB$$e1d08fdc targetClass$$EnhancerByCGLIB$$e1d08fdc = (TargetClass$$EnhancerByCGLIB$$e1d08fdc)paramObject;
    if (!targetClass$$EnhancerByCGLIB$$e1d08fdc.CGLIB$BOUND) {
      targetClass$$EnhancerByCGLIB$$e1d08fdc.CGLIB$BOUND = true;
      if (CGLIB$THREAD_CALLBACKS.get() == null) {
        CGLIB$THREAD_CALLBACKS.get();
        if (CGLIB$STATIC_CALLBACKS == null)
          return; 
      } 
      targetClass$$EnhancerByCGLIB$$e1d08fdc.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])CGLIB$THREAD_CALLBACKS.get())[0];
    } 
  }
  
  public Object newInstance(Callback[] paramArrayOfCallback) {
    CGLIB$SET_THREAD_CALLBACKS(paramArrayOfCallback);
    CGLIB$SET_THREAD_CALLBACKS(null);
    return new TargetClass$$EnhancerByCGLIB$$e1d08fdc();
  }
  
  public Object newInstance(Callback paramCallback) {
    CGLIB$SET_THREAD_CALLBACKS(new Callback[] { paramCallback });
    CGLIB$SET_THREAD_CALLBACKS(null);
    return new TargetClass$$EnhancerByCGLIB$$e1d08fdc();
  }
  
  public Object newInstance(Class[] paramArrayOfClass, Object[] paramArrayOfObject, Callback[] paramArrayOfCallback) {
    // Byte code:
    //   0: aload_3
    //   1: invokestatic CGLIB$SET_THREAD_CALLBACKS : ([Lorg/springframework/cglib/proxy/Callback;)V
    //   4: new com/daniel/dynamicproxy/cglibproxy/TargetClass$$EnhancerByCGLIB$$e1d08fdc
    //   7: dup
    //   8: aload_1
    //   9: dup
    //   10: arraylength
    //   11: tableswitch default -> 35, 0 -> 28
    //   28: pop
    //   29: invokespecial <init> : ()V
    //   32: goto -> 49
    //   35: goto -> 38
    //   38: pop
    //   39: new java/lang/IllegalArgumentException
    //   42: dup
    //   43: ldc 'Constructor not found'
    //   45: invokespecial <init> : (Ljava/lang/String;)V
    //   48: athrow
    //   49: aconst_null
    //   50: invokestatic 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:
      
    } 
    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[] { (Callback)this.CGLIB$CALLBACK_0 };
  }
  
  public void setCallbacks(Callback[] paramArrayOfCallback) {
    this.CGLIB$CALLBACK_0 = (MethodInterceptor)paramArrayOfCallback[0];
  }
}

FastClass机制

CgLib采用FastClass机制来代替反射实现对被拦截的方法进行调用。

在调用代理类的interceptor方法后,会调用代理方法MethodProxy中的invokeSuper方法

public Object invokeSuper(Object obj, Object[] args) throws Throwable {
	try {
		init();
		FastClassInfo fci = fastClassInfo;
		// 调用FastClassInfo中的invoke方法,执行代理方法
		return fci.f2.invoke(fci.i2, obj, args);
	}
	catch (InvocationTargetException e) {
		throw e.getTargetException();
	}
}

// init方法
private void init() {
	if (fastClassInfo == null) {
		synchronized (initLock) {
			if (fastClassInfo == null) {
				CreateInfo ci = createInfo;

				FastClassInfo fci = new FastClassInfo();
				fci.f1 = helper(ci, ci.c1);
				fci.f2 = helper(ci, ci.c2);
				// 获取方法的索引
				fci.i1 = fci.f1.getIndex(sig1);
				fci.i2 = fci.f2.getIndex(sig2);
				fastClassInfo = fci;
				createInfo = null;
			}
		}
	}
}

总结

当我们调用代理类的方法时,首先判断是否实现了MethodInterceptor接口,如果没有的话,直接调用方法;

如果实现了,那么调用方法时就会被拦截,在方法拦截器中会对目标类的所有方法建立索引,将目标类的每个方法的引用保存到数组中,然后通过数组下标的方式直接调用对应的方法。
使用这种方式的原因是因为反射的效率相对于new是比较低的。

建立完索引后,就会执行代理类的invoke方法(FastClass)

最后在invoke方法内部调用类似CGLIB$sayHi$的目标方法