cglib动态代理的实现原理
1、示例代码
package com.zcqby.proxy.cglib;
public class MyCalculator {
public int add (int i, int j) {
int result = i + j;
return result;
}
public int sub (int i, int j) {
int result = i - j;
return result;
}
public int mult (int i, int j) {
int result = i * j;
return result;
}
public int div (int i, int j) {
int result = i / j;
return result;
}
}
package com.zcqby.proxy.cglib;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class MyCglib implements MethodInterceptor {
@Override
public Object intercept (Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object o1 = methodProxy.invokeSuper(o, objects);
return o1;
}
}
package com.zcqby.proxy.cglib;
import org.springframework.cglib.core.DebuggingClassWriter;
import org.springframework.cglib.proxy.Enhancer;
public class MyTest {
public static void main (String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"d:\\code" );
Enhancer enhancer = new Enhancer ();
enhancer.setSuperclass(MyCalculator.class);
enhancer.setCallback(new MyCglib ());
MyCalculator myCalculator = (MyCalculator) enhancer.create();
myCalculator.add(1 ,1 );
System.out.println(myCalculator.getClass());
}
}
2、源码跟踪
2.1、注意事项:
调试的时候, 如果想更详细的了解原理, 需要将断点打在 Enhancer enhancer = new Enhancer();
这里, 原因是 这边就已经创建了 缓存对象 ClassLoaderData
。
在常见过程中,我们要了解一个抽象类 FastClass
, CGLib
在运行时通过 FastClass
内 的Generator
这个内部类将其子类动态生成出来 ,然后再利用 ClassLoader
将 生成子类加载进JVM 里面去。
2.2、具体debug流程以及图片展示
2.2.1、Enchancer
类 创建对象 Enhancer enhancer = new Enhancer()
EnhancerKey
作为参数传递给 KeyFactory.create(...)
方法
gen.create()
方法执行, 用于创建 Enhancer的代理对象
gen
对象是 KeyFactory
类生成的对象
KeyFactory
父类是 KeyFactory$Generator@482
执行 KeyFactory$Generator@482
对象的create
方法(super.create(keyInterface.getName()))
执行new ClassLoaderData(loader)
--> 其实这里面就是包装了两个函数式的接口, 在这边还没开始调用。
执行data.get(...)
注意的是, 这里的 data
就是我们上面通过 new ClassLoaderData(...)
生成的对象。
执行 generatedClassses.get(gen)
, 注意这里的 generatedClasses
是一个缓存对象LoadCache
对象。
跳出apply
方法后, 执行 this.createEntry(key, cacheKey, v)
通过 task.run()
-> FutureTask
对象的 call
方法 --> Func函数式接口对象的load.apply
方法。
如下图所示, gen.generate(...)
这就是正儿八经的生成字节码文件地方了。
执行 gen.generate()
生成器的生成方法
有了名字之后就开始生成字节码文件了 ,执行 byte[] b = strategy.generate(this);
public void generateClass (ClassVisitor v) {
ClassEmitter ce = new ClassEmitter (v);
Method newInstance = ReflectUtils.findNewInstance(keyInterface);
if (!newInstance.getReturnType().equals(Object.class)) {
throw new IllegalArgumentException ("newInstance method must return Object" );
}
Type[] parameterTypes = TypeUtils.getTypes(newInstance.getParameterTypes());
ce.begin_class(Constants.V1_8,
Constants.ACC_PUBLIC,
getClassName(),
KEY_FACTORY,
new Type []{Type.getType(keyInterface)},
Constants.SOURCE_FILE);
EmitUtils.null_constructor(ce);
EmitUtils.factory_method(ce, ReflectUtils.getSignature(newInstance));
int seed = 0 ;
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC,
TypeUtils.parseConstructor(parameterTypes),
null );
e.load_this();
e.super_invoke_constructor();
e.load_this();
List<FieldTypeCustomizer> fieldTypeCustomizers = getCustomizers(FieldTypeCustomizer.class);
for (int i = 0 ; i < parameterTypes.length; i++) {
Type parameterType = parameterTypes[i];
Type fieldType = parameterType;
for (FieldTypeCustomizer customizer : fieldTypeCustomizers) {
fieldType = customizer.getOutType(i, fieldType);
}
seed += fieldType.hashCode();
ce.declare_field(Constants.ACC_PRIVATE | Constants.ACC_FINAL,
getFieldName(i),
fieldType,
null );
e.dup();
e.load_arg(i);
for (FieldTypeCustomizer customizer : fieldTypeCustomizers) {
customizer.customize(e, i, parameterType);
}
e.putfield(getFieldName(i));
}
e.return_value();
e.end_method();
e = ce.begin_method(Constants.ACC_PUBLIC, HASH_CODE, null );
int hc = (constant != 0 ) ? constant : PRIMES[(Math.abs(seed) % PRIMES.length)];
int hm = (multiplier != 0 ) ? multiplier : PRIMES[(Math.abs(seed * 13 ) % PRIMES.length)];
e.push(hc);
for (int i = 0 ; i < parameterTypes.length; i++) {
e.load_this();
e.getfield(getFieldName(i));
EmitUtils.hash_code(e, parameterTypes[i], hm, customizers);
}
e.return_value();
e.end_method();
e = ce.begin_method(Constants.ACC_PUBLIC, EQUALS, null );
Label fail = e.make_label();
e.load_arg(0 );
e.instance_of_this();
e.if_jump(CodeEmitter.EQ, fail);
for (int i = 0 ; i < parameterTypes.length; i++) {
e.load_this();
e.getfield(getFieldName(i));
e.load_arg(0 );
e.checkcast_this();
e.getfield(getFieldName(i));
EmitUtils.not_equals(e, parameterTypes[i], fail, customizers);
}
e.push(1 );
e.return_value();
e.mark(fail);
e.push(0 );
e.return_value();
e.end_method();
e = ce.begin_method(Constants.ACC_PUBLIC, TO_STRING, null );
e.new_instance(Constants.TYPE_STRING_BUFFER);
e.dup();
e.invoke_constructor(Constants.TYPE_STRING_BUFFER);
for (int i = 0 ; i < parameterTypes.length; i++) {
if (i > 0 ) {
e.push(", " );
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING);
}
e.load_this();
e.getfield(getFieldName(i));
EmitUtils.append_string(e, parameterTypes[i], EmitUtils.DEFAULT_DELIMITERS, customizers);
}
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, TO_STRING);
e.return_value();
e.end_method();
ce.end_class();
}
上面就已经生成了字节码, 下面就是返回到调用方法去, 继续执行:
1、将 gen
生成器对象加载到内存中去
2、返回生成器对象。
最终返回到data.get(...)
, 生成一个 obj
,然后判断是否是 Class
,如果是 , 就进行实例化
至此,上面这一坨, 都是因为我们在创建 enhancer
对象的时候, 需要使用到enhancerKey的一个代理对象, 因此, 上面这边结束,会生成的是一个 enhancerKeY
的一个代理的对象。
下面就是通过 Enhancer enhancer = new Enhancer()
生成enhancer
对象 (非代理对象)
ps: EnhancerKey
这个代理对象中, 有一个 newInstance
方法, 后面需要使用
2.2.2、MyCalculator
动态代理类的创建
package com.mashibing.proxy.cglib;
import org.springframework.cglib.core.DebuggingClassWriter;
import org.springframework.cglib.proxy.Enhancer;
public class MyTest {
public static void main (String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"d:\\code" );
Enhancer enhancer = new Enhancer ();
enhancer.setSuperclass(MyCalculator.class);
enhancer.setCallback(new MyCglib ());
MyCalculator myCalculator = (MyCalculator) enhancer.create();
myCalculator.add(1 ,1 );
System.out.println(myCalculator.getClass());
}
}
下面就是创建 MyCalculator
动态代理对象了, 入口语句 MyCalculator myCalculator = (MyCalculator) enhancer.create();
调用父类即AbstractClassGenerator的创建代理类(``MyCalculator) -->
Object result = super.create(key);`
最终又走到了 AbstractClassGenerator
中的create
方法 。--> 和之前创建 EnhancerKey 代理对象执行相同的方法。
不一样的是 ,由于已经创建过 KEY_FACTORY (EnhancerKey) 的代理预想, 所以, 此时 CACHE
已经不为空了。
下面就是和 生成 EnhancerKey
一样的执行步骤
这里需要注意的是:
此时, 由于生成 的obj 不是 Class字节码文件, 所以, 不需要 执行firstInstance(...)
,而是执行nextInstance(obj)
;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
2019-07-07 Django 之 rest_framework 分页器使用