CGLIB动态代理原理分析

CGLIB动态代理原理分析

前提

前一篇文章介绍了CGLIB中常用的API,实际上使用了EnhancerMethodInterceptor之后会生成代理子类,这篇文章就是分析一下CGLIB动态代理的原理。

CGLIB动态代理原理分析

我们经常说CGLIB的动态代理的底层通过被代理类生成代理子类实现的,那么下面我们就分析一下生成的子类到底是什么样的。开启CGLIB的debug模式,输出它生成的类到指定的目录:

public class DebuggingCglibDemo {

private static final String METHOD_NAME = "sayHello";

public static void main(String[] args) throws Exception {
String location = DebuggingCglibDemo.class.getResource("").getPath() + "debugging/";
System.out.println("location -> " + location);
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, location);
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object result;
if (METHOD_NAME.equals(method.getName())) {
System.out.println("Before invoking sayHello...");
result = methodProxy.invokeSuper(obj, objects);
System.out.println("After invoking sayHello...");
} else {
result = methodProxy.invokeSuper(obj, objects);
}
return result;
}
});
SampleClass sampleClass = (SampleClass) enhancer.create();
System.out.println(sampleClass.sayHello("throwable"));
}
}

输出结果:

location -> /D:/Projects/cglib-seed/target/classes/club/throwable/cglib/debugging/
CGLIB debugging enabled, writing to '/D:/Projects/cglib-seed/target/classes/club/throwable/cglib/debugging/'
Before invoking sayHello...
After invoking sayHello...
throwable say hello!

这个时候,看下target下面生成的类如下:

c-d-p-1

一共有五个类:

../net.sf.cglib包下:

MethodWrapper$MethodWrapperKey$$KeyFactoryByCGLIB$$d45e49f7.class
Enhancer$EnhancerKey$$KeyFactoryByCGLIB$$7fb24d72.class

这两个类主要很缓存的Key相关,这里不做详细展开。

用户自定义包../club/throwable/cglib包下:

  • SampleClass$$EnhancerByCGLIB$$53c7afed$$FastClassByCGLIB$$da5c8621.class
  • SampleClass$$EnhancerByCGLIB$$53c7afed.class
  • SampleClass$$FastClassByCGLIB$$cf1a549b.class

这三个就是实际使用到的子类,其中有一个是被代理类的直接子类SampleClass$$EnhancerByCGLIB$$53c7afed,其他的两个是FastClass

接着我们先看一下SampleClass$$EnhancerByCGLIB$$53c7afed这个类的源码:

与Java原生代理类似,仍然以静态变量保存了指向代理方法的引用
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;
//每个函数有两个反射方法,一个是通过原生反射获得的,另外一个是通过Cglib构建的。
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$equals$1$Method;
private static final MethodProxy CGLIB$equals$1$Proxy;
private static final Method CGLIB$toString$2$Method;
private static final MethodProxy CGLIB$toString$2$Proxy;
private static final Method CGLIB$hashCode$3$Method;
private static final MethodProxy CGLIB$hashCode$3$Proxy;
private static final Method CGLIB$clone$4$Method;
private static final MethodProxy CGLIB$clone$4$Proxy;

//这里通过静态代码块初始化上面用到的静态变量,主要使用到反射
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
Class var0 = Class.forName("club.throwable.cglib.SampleClass$$EnhancerByCGLIB$$53c7afed");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
CGLIB$equals$1$Method = var10000[0];
CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
CGLIB$toString$2$Method = var10000[1];
CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
CGLIB$hashCode$3$Method = var10000[2];
CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
CGLIB$clone$4$Method = var10000[3];
CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
CGLIB$sayHello$0$Method = ReflectUtils.findMethods(new String[]{"sayHello", "(Ljava/lang/String;)Ljava/lang/String;"}, (var1 = Class.forName("club.throwable.cglib.SampleClass")).getDeclaredMethods())[0];
CGLIB$sayHello$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)Ljava/lang/String;", "sayHello", "CGLIB$sayHello$0");
}

//这个方法就是直接调用原来的被代理类(父类)的方法
final String CGLIB$sayHello$0(String var1) {
return super.sayHello(var1);
}
//这个方法就是通过方法代理进行回调,里面用到了Callback实例
public final String sayHello(String var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}

return var10000 != null ? (String)var10000.intercept(this, CGLIB$sayHello$0$Method, new Object[]{var1}, CGLIB$sayHello$0$Proxy) : super.sayHello(var1);
}

final boolean CGLIB$equals$1(Object var1) {
return super.equals(var1);
}

public final boolean equals(Object var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}

if (var10000 != null) {
Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
return var2 == null ? false : (Boolean)var2;
} else {
return super.equals(var1);
}
}

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

public final String toString() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}

return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
}

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

public final int hashCode() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}

if (var10000 != null) {
Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
return var1 == null ? 0 : ((Number)var1).intValue();
} else {
return super.hashCode();
}
}

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

protected final Object clone() throws CloneNotSupportedException {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}

return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
}

public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -1816210712:
if (var10000.equals("sayHello(Ljava/lang/String;)Ljava/lang/String;")) {
return CGLIB$sayHello$0$Proxy;
}
break;
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$4$Proxy;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return CGLIB$equals$1$Proxy;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return CGLIB$toString$2$Proxy;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return CGLIB$hashCode$3$Proxy;
}
}

return null;
}

public SampleClass$$EnhancerByCGLIB$$53c7afed() {
CGLIB$BIND_CALLBACKS(this);
}

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

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

private static final void CGLIB$BIND_CALLBACKS(Object var0) {
SampleClass$$EnhancerByCGLIB$$53c7afed var1 = (SampleClass$$EnhancerByCGLIB$$53c7afed)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (CGLIB$STATIC_CALLBACKS == null) {
return;
}
}

var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
}

}

public Object newInstance(Callback[] var1) {
CGLIB$SET_THREAD_CALLBACKS(var1);
SampleClass$$EnhancerByCGLIB$$53c7afed var10000 = new SampleClass$$EnhancerByCGLIB$$53c7afed();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}

public Object newInstance(Callback var1) {
CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
SampleClass$$EnhancerByCGLIB$$53c7afed var10000 = new SampleClass$$EnhancerByCGLIB$$53c7afed();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
}

public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
CGLIB$SET_THREAD_CALLBACKS(var3);
SampleClass$$EnhancerByCGLIB$$53c7afed var10000 = new SampleClass$$EnhancerByCGLIB$$53c7afed;
switch(var1.length) {
case 0:
var10000.<init>();
CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
return var10000;
default:
throw new IllegalArgumentException("Constructor not found");
}
}

public Callback getCallback(int var1) {
CGLIB$BIND_CALLBACKS(this);
MethodInterceptor var10000;
switch(var1) {
case 0:
var10000 = this.CGLIB$CALLBACK_0;
break;
default:
var10000 = null;
}

return var10000;
}

public void setCallback(int var1, Callback var2) {
switch(var1) {
case 0:
this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
default:
}
}

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

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

static {
CGLIB$STATICHOOK1();
}
}

这个类十分长,因为里面有很多的变量,它们都通过了静态代码块使用反射初始化。类的代码比JDK动态代理的子类多,因此生成效率会比较低。相关比较重要的注释已经写在类中,我们最主要关注两点:

  • 第一点:
private static final Method CGLIB$sayHello$0$Method;
private static final MethodProxy CGLIB$sayHello$0$Proxy;

这两个静态变量都是指向sayHello这个方法,CGLIB$sayHello$0$Method直接指向父类方法,CGLIB$sayHello$0$Proxy是CGLIB生成的方法代理。

  • 第二点:
//这个方法就是直接调用原来的被代理类(父类)的方法
final String CGLIB$sayHello$0(String var1) {
return super.sayHello(var1);
}
//这个方法就是通过方法代理进行回调,里面用到了Callback实例
public final String sayHello(String var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
//如果找不到Callback会直接调用父类的原方法
return var10000 != null ? (String)var10000.intercept(this, CGLIB$sayHello$0$Method, new Object[]{var1}, CGLIB$sayHello$0$Proxy) : super.sayHello(var1);
}

也就是如果想要启用CGLIB的回调,我们主观上应该是这样操作的:

SampleClass$$EnhancerByCGLIB$$53c7afed sample = new SampleClass$$EnhancerByCGLIB$$53c7afed();
sample.sayHello("doge");

但是由于这个代理类是动态生成的,只能通过反射调用。

那么,剩下的两个FastClass的作用是什么?我们先看一下MethodProxyinvoke()invokeSuper()方法:

  //初始化FastClass中的index索引
private void init() {
if (this.fastClassInfo == null) {
Object var1 = this.initLock;
synchronized(this.initLock) {
if (this.fastClassInfo == null) {
MethodProxy.CreateInfo ci = this.createInfo;
MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();
fci.f1 = helper(ci, ci.c1);
fci.f2 = helper(ci, ci.c2);
fci.i1 = fci.f1.getIndex(this.sig1);
fci.i2 = fci.f2.getIndex(this.sig2);
this.fastClassInfo = fci;
this.createInfo = null;
}
}
}
}

public Object invoke(Object obj, Object[] args) throws Throwable {
try {
this.init();
MethodProxy.FastClassInfo fci = this.fastClassInfo;
return fci.f1.invoke(fci.i1, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
} catch (IllegalArgumentException var5) {
if (this.fastClassInfo.i1 < 0) {
throw new IllegalArgumentException("Protected method: " + this.sig1);
} else {
throw var5;
}
}
}

public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
this.init();
MethodProxy.FastClassInfo fci = this.fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
}
}

这里,两个方法各自使用了不同的FastClassInfo实例fci.f2fci.f2。其中,SampleClass$$FastClassByCGLIB$$cf1a549b.class是对应于父类,而SampleClass$$EnhancerByCGLIB$$53c7afed$$FastClassByCGLIB$$da5c8621是对应于CGLIB生成的被代理类的子类。下面展开SampleClass$$EnhancerByCGLIB$$53c7afed$$FastClassByCGLIB$$da5c8621的源码:

public class SampleClass$$EnhancerByCGLIB$$53c7afed$$FastClassByCGLIB$$da5c8621 extends FastClass {
public SampleClass$$EnhancerByCGLIB$$53c7afed$$FastClassByCGLIB$$da5c8621(Class var1) {
super(var1);
}

public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case -2055565910:
if (var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
return 10;
}
break;
case -1882565338:
if (var10000.equals("CGLIB$equals$1(Ljava/lang/Object;)Z")) {
return 18;
}
break;
case -1816210712:
if (var10000.equals("sayHello(Ljava/lang/String;)Ljava/lang/String;")) {
return 7;
}
break;
case -1457535688:
if (var10000.equals("CGLIB$STATICHOOK1()V")) {
return 15;
}
break;
case -1411842725:
if (var10000.equals("CGLIB$hashCode$3()I")) {
return 19;
}
break;
case -894172689:
if (var10000.equals("newInstance(Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 5;
}
break;
case -623122092:
if (var10000.equals("CGLIB$findMethodProxy(Lnet/sf/cglib/core/Signature;)Lnet/sf/cglib/proxy/MethodProxy;")) {
return 14;
}
break;
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return 3;
}
break;
case -419626537:
if (var10000.equals("setCallbacks([Lnet/sf/cglib/proxy/Callback;)V")) {
return 13;
}
break;
case 560567118:
if (var10000.equals("setCallback(ILnet/sf/cglib/proxy/Callback;)V")) {
return 8;
}
break;
case 811063227:
if (var10000.equals("newInstance([Ljava/lang/Class;[Ljava/lang/Object;[Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 6;
}
break;
case 973717575:
if (var10000.equals("getCallbacks()[Lnet/sf/cglib/proxy/Callback;")) {
return 11;
}
break;
case 1221173700:
if (var10000.equals("newInstance([Lnet/sf/cglib/proxy/Callback;)Ljava/lang/Object;")) {
return 4;
}
break;
case 1230699260:
if (var10000.equals("getCallback(I)Lnet/sf/cglib/proxy/Callback;")) {
return 12;
}
break;
case 1298742135:
if (var10000.equals("CGLIB$sayHello$0(Ljava/lang/String;)Ljava/lang/String;")) {
return 16;
}
break;
case 1306468936:
if (var10000.equals("CGLIB$toString$2()Ljava/lang/String;")) {
return 20;
}
break;
case 1584330438:
if (var10000.equals("CGLIB$SET_STATIC_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
return 9;
}
break;
case 1800494055:
if (var10000.equals("CGLIB$clone$4()Ljava/lang/Object;")) {
return 17;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return 0;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return 1;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return 2;
}
}

return -1;
}

public int getIndex(String var1, Class[] var2) {
switch(var1.hashCode()) {
case -2012993625:
if (var1.equals("sayHello")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.String")) {
return 7;
}
}
}
break;
case -1983192202:
if (var1.equals("CGLIB$sayHello$0")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.String")) {
return 16;
}
}
}
break;
case -1776922004:
if (var1.equals("toString")) {
switch(var2.length) {
case 0:
return 1;
}
}
break;
case -1295482945:
if (var1.equals("equals")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.Object")) {
return 0;
}
}
}
break;
case -1053468136:
if (var1.equals("getCallbacks")) {
switch(var2.length) {
case 0:
return 11;
}
}
break;
case -124978609:
if (var1.equals("CGLIB$equals$1")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("java.lang.Object")) {
return 18;
}
}
}
break;
case -60403779:
if (var1.equals("CGLIB$SET_STATIC_CALLBACKS")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 9;
}
}
}
break;
case -29025555:
if (var1.equals("CGLIB$hashCode$3")) {
switch(var2.length) {
case 0:
return 19;
}
}
break;
case 85179481:
if (var1.equals("CGLIB$SET_THREAD_CALLBACKS")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 10;
}
}
}
break;
case 94756189:
if (var1.equals("clone")) {
switch(var2.length) {
case 0:
return 3;
}
}
break;
case 147696667:
if (var1.equals("hashCode")) {
switch(var2.length) {
case 0:
return 2;
}
}
break;
case 161998109:
if (var1.equals("CGLIB$STATICHOOK1")) {
switch(var2.length) {
case 0:
return 15;
}
}
break;
case 495524492:
if (var1.equals("setCallbacks")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 13;
}
}
}
break;
case 1154623345:
if (var1.equals("CGLIB$findMethodProxy")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("net.sf.cglib.core.Signature")) {
return 14;
}
}
}
break;
case 1543336189:
if (var1.equals("CGLIB$toString$2")) {
switch(var2.length) {
case 0:
return 20;
}
}
break;
case 1811874389:
if (var1.equals("newInstance")) {
switch(var2.length) {
case 1:
String var10001 = var2[0].getName();
switch(var10001.hashCode()) {
case -845341380:
if (var10001.equals("net.sf.cglib.proxy.Callback")) {
return 5;
}
break;
case 1730110032:
if (var10001.equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 4;
}
}
case 2:
default:
break;
case 3:
if (var2[0].getName().equals("[Ljava.lang.Class;") && var2[1].getName().equals("[Ljava.lang.Object;") && var2[2].getName().equals("[Lnet.sf.cglib.proxy.Callback;")) {
return 6;
}
}
}
break;
case 1817099975:
if (var1.equals("setCallback")) {
switch(var2.length) {
case 2:
if (var2[0].getName().equals("int") && var2[1].getName().equals("net.sf.cglib.proxy.Callback")) {
return 8;
}
}
}
break;
case 1905679803:
if (var1.equals("getCallback")) {
switch(var2.length) {
case 1:
if (var2[0].getName().equals("int")) {
return 12;
}
}
}
break;
case 1951977610:
if (var1.equals("CGLIB$clone$4")) {
switch(var2.length) {
case 0:
return 17;
}
}
}

return -1;
}

public int getIndex(Class[] var1) {
switch(var1.length) {
case 0:
return 0;
default:
return -1;
}
}

public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
53c7afed var10000 = (53c7afed)var2;
int var10001 = var1;

try {
switch(var10001) {
case 0:
return new Boolean(var10000.equals(var3[0]));
case 1:
return var10000.toString();
case 2:
return new Integer(var10000.hashCode());
case 3:
return var10000.clone();
case 4:
return var10000.newInstance((Callback[])var3[0]);
case 5:
return var10000.newInstance((Callback)var3[0]);
case 6:
return var10000.newInstance((Class[])var3[0], (Object[])var3[1], (Callback[])var3[2]);
case 7:
return var10000.sayHello((String)var3[0]);
case 8:
var10000.setCallback(((Number)var3[0]).intValue(), (Callback)var3[1]);
return null;
case 9:
53c7afed.CGLIB$SET_STATIC_CALLBACKS((Callback[])var3[0]);
return null;
case 10:
53c7afed.CGLIB$SET_THREAD_CALLBACKS((Callback[])var3[0]);
return null;
case 11:
return var10000.getCallbacks();
case 12:
return var10000.getCallback(((Number)var3[0]).intValue());
case 13:
var10000.setCallbacks((Callback[])var3[0]);
return null;
case 14:
return 53c7afed.CGLIB$findMethodProxy((Signature)var3[0]);
case 15:
53c7afed.CGLIB$STATICHOOK1();
return null;
case 16:
return var10000.CGLIB$sayHello$0((String)var3[0]);
case 17:
return var10000.CGLIB$clone$4();
case 18:
return new Boolean(var10000.CGLIB$equals$1(var3[0]));
case 19:
return new Integer(var10000.CGLIB$hashCode$3());
case 20:
return var10000.CGLIB$toString$2();
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}

throw new IllegalArgumentException("Cannot find matching method/constructor");
}

public Object newInstance(int var1, Object[] var2) throws InvocationTargetException {
53c7afed var10000 = new 53c7afed;
53c7afed var10001 = var10000;
int var10002 = var1;

try {
switch(var10002) {
case 0:
var10001.<init>();
return var10000;
}
} catch (Throwable var3) {
throw new InvocationTargetException(var3);
}

throw new IllegalArgumentException("Cannot find matching method/constructor");
}

public int getMaxIndex() {
return 20;
}
}

这个类更加长,但是其实大部分都是switch-case的代码块,它的功能就是为方法的调用添加基于整型数字的索引,主要目的是为了减少反射调用的时间,将反射调用转化为直接调用。简单来说,invokeSuper的流程就是这样的

  • 通过MethodProxy的init方法,用当前方法的Signature(签名)构建两个FastClass实例(当然,这里会做缓存)和当前方法对应的index,存放在FastClassInfo实例中。
  • 通过FastClassInfo中的FastClass实例和index,在FastClass中找到对应的方法(在switch-case块中基于整数索引index进行查找)直接调用。

直观来看,CGLIB在类生成期间的操作会相对耗时,而且生成的类数目比较多,会占据大量永久代或者元空间的内存。子类一旦生成,后面的方法调用就会变成搜索方法索引和直接调用,这样的操作在特定的条件下效率会比JDK的反射高。这里特定的场景是指CGLIB子类中的switch-case块不大并且当前调用的方法的index在switch-case块的前部而不是中后部(简单来说就是子类中的方法要尽量少从而提高switch-case中的搜寻效率)。详细可以参考这篇性能对比的文章:cglib和jdk动态代理调用性能测

小结

CGLIB提供了许多基于代码生成的高级功能的API,可以在通过上面的例子熟悉它的使用,并且在合适的场景用于实战中。可能最常用到的是基于Enhancer的动态代理,这里总结一下CGLIB和JDK动态代理的区别(老生常谈):

  • JDK动态代理只能够对接口进行代理,不能对普通的类进行代理(因为所有生成的代理类的父类为Proxy,Java类继承机制不允许多重继承);CGLIB能够代理普通类,但是该普通类必须能够被继承(不能用final修饰符)。
  • JDK动态代理使用Java原生的反射API进行操作,在生成类上比较高效;CGLIB使用ASM框架直接对字节码进行修改,使用了FastClass的特性,在某些情况下类的方法执行会比较高效。

(本文完 e-a-20181216 c-1-d)

文章作者: throwable
文章链接: http://www.throwable.club/2018/12/16/cglib-dynamic-proxy-analyze/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Throwable
❤支付宝打赏❤
❤微信打赏❤