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$
的目标方法