CGLIB代理使用示例与底层原理解析
CGLIB常用使用示例:
目标类
public class Todo {
public void doString(String desc) {
System.out.println("doString: " + desc);
}
}
代理生成类
public class ProxyInstance implements MethodInterceptor {
public <T> T getInstance(Class<T> klass) {
Enhancer enhancer = new Enhancer();
/*
* 设置父类型,用于生成代理的子类
*/
enhancer.setSuperclass(klass);
/*
* 设置实现Callback接口的实例对象
* 这里为MethodInterceptor对象
*/
enhancer.setCallback(this);
/*
* create()用于创建代理类对象
* createClass()用于生成java字节码
*/
return (T) enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("proxy before");
Object obj= methodProxy.invokeSuper(o, objects);
System.out.println("proxy after");
return obj;
}
}
测试类
public class Test {
public static void main(String[] args) {
String path = Test.class.getClassLoader().getResource("").getPath();
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, path + "cglib");
Todo todo=new ProxyInstance().getInstance(Todo.class);
todo.doString("------ nothing-------- ");
}
}
控制台
CGLIB debugging enabled, writing to '/E:/ideaspace/demo/demo/target/classes/cglib'
proxy before
doString: ------ nothing--------
proxy after
ASM(assembly):汇编的缩写,是java的一个字节码级别的编程框架,它可以动态生成Class的字节码文件,CGLIB以及Groovy等都是基于ASM实现动态语言特性的,在CGLIB的代理中主要用于生成类文件,实现方式为动态生成继承了目标类的代理类。
maven依赖
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>8.0.1</version>
</dependency>
针对示例的目标类,生成类过多这里只展示主要代码:注意所有生成的类都会加载到JVM中
// 代理类相关的生成类
Todo$$EnhancerByCGLIB$$939b412c$$FastClassByCGLIB$$b6c5bc7f.class
Todo$$EnhancerByCGLIB$$939b412c.class // 代理类
Todo$$FastClassByCGLIB$$9f944a58.class
//其他类
core/MethodWrapper$MethodWrapperKey$$KeyFactoryByCGLIB$$d45e49f7.class
proxy/Enhancer$EnhancerKey$$KeyFactoryByCGLIB$$7fb24d72.class
代理类描述
// 通过继承方式来实现代理,目标类成为了父类supper。通过继承实现也附带了继承的缺点,注意final类型和final方法的坑
public class Todo$$EnhancerByCGLIB$$939b412c extends Todo implements Factory {...}
针对方法的静态处理
static void CGLIB$STATICHOOK1() {
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
// 当前代理类
Class var0 = Class.forName("cn.tinyice.demo.proxy.cglib.Todo$$EnhancerByCGLIB$$939b412c");
Class var1;
// 通过反射获取java.lang.Object声明的所有方法(不包括继承的方法,这里也不会有)中的equals、toString、hashCode、clone方法,准备重写
// 注意 这里 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());
// 对每个方法获取其Method对象$Method以及代理对象$Proxy
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");
// 获取目标类用户方法doString的Method对象$Method以及代理对象$Proxy,注意这里var1赋值
CGLIB$doString$0$Method = ReflectUtils.findMethods(new String[]{"doString", "(Ljava/lang/String;)V"}, (var1 = Class.forName("cn.tinyice.demo.proxy.cglib.Todo")).getDeclaredMethods())[0];
CGLIB$doString$0$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/String;)V", "doString", "CGLIB$doString$0");
}
代理方法描述
public final void doString(String var1) {
// 方法拦截器:从callBack中获取,这里为ProxyInstance
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
// 具有方法拦截器则执行其拦截方法
if (var10000 != null) {
// 参数: 代理类对象、原方法对象、参数对象、代理方法对象
var10000.intercept(this, CGLIB$doString$0$Method, new Object[]{var1}, CGLIB$doString$0$Proxy);
} else {
// 不拦截方法则直接调用原方法
super.doString(var1);
}
}
到这里已经执行到了ProxyInstance#intercept,然后调用methodProxy.invokeSuper(o, objects);
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
// 初始化MethodProxy实例,注意在调用时才初始化的
this.init();
// 获取FastClass
MethodProxy.FastClassInfo fci = this.fastClassInfo;
// 调用FastClassInfo的FastClass2的invoke,参数为方法签名下标,调用对象、方法参数
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
}
}
private void init() {
if (this.fastClassInfo == null) {
synchronized(this.initLock) {
if (this.fastClassInfo == null) {
MethodProxy.CreateInfo ci = this.createInfo;
MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();
// fastClass1 生成 ,c1为MethodProxy.create的第一个参数,目标类
// 生成类名称前缀=参数2的类名称+$$FastClassByCGLIB$$Integer.toHexString(hashCode)
fci.f1 = helper(ci, ci.c1);
// fastClass2生成,c2为MethodProxy.create的第二个参数,代理类Class
fci.f2 = helper(ci, ci.c2);
// 调用getIndex获取下标,参数为方法签名,二者一一映射,这里使用switch语句来提高效率
fci.i1 = fci.f1.getIndex(this.sig1);
fci.i2 = fci.f2.getIndex(this.sig2);
// 实例构建完毕
this.fastClassInfo = fci;
this.createInfo = null;
}
}
}
}
-
目标类使用$$FastClass1进行调用
-
代理类使用$$FastClass2进行调用
-
$$FastClass都在调用时触发生成