动态代理的实现原理
CGLIB(Code Generation Library)动态代理的实现原理基于字节码生成技术和继承机制,其核心在于运行时生成目标类的子类,通过方法重写实现代理逻辑。以下是具体实现原理和示例的详细说明:
一、核心实现机制
-
子类继承
CGLIB通过ASM框架在内存中生成目标类的子类,代理类继承目标类并重写所有非final方法。例如,若目标类是UserService,生成的代理类结构类似UserService$$EnhancerByCGLIB$$xxx,并重写addUser()方法。 -
方法拦截
代理类重写的方法会调用MethodInterceptor.intercept()方法,开发者可在该方法中插入增强逻辑(如日志、事务等)。例如:public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) { // 前置增强 Object result = proxy.invokeSuper(obj, args); // 调用父类(目标类)的原始方法 // 后置增强 return result; } -
FastClass优化
CGLIB生成FastClass类,通过方法索引直接调用目标方法,避免反射带来的性能损耗。例如,代理类会生成两个FastClass文件,分别对应目标类和代理类的方法索引。
二、为何调用原方法会变成代理方法?
以示例说明:
-
原始类定义
public class Coder { public void work() { System.out.println("认真写bug..."); } } -
生成代理类
CGLIB生成子类Coder$$EnhancerByCGLIB$$xxx,并重写work()方法:public class Coder$$EnhancerByCGLIB$$xxx extends Coder { private MethodInterceptor interceptor; public void work() { interceptor.intercept(this, MethodProxy.create(Coder.class, "work"), new Object[0], super.work); } } -
调用流程
当用户调用proxy.work()时:- 步骤1:实际调用的是代理类
Coder$$EnhancerByCGLIB$$xxx的work()方法。 - 步骤2:代理类方法内部调用
MethodInterceptor.intercept(),执行增强逻辑。 - 步骤3:通过
proxy.invokeSuper()调用父类(即原始Coder类的work()方法)。
- 步骤1:实际调用的是代理类
三、具体实现示例
-
目标类与拦截器定义
public class Service { public void process() { System.out.println("业务逻辑"); } } public class LogInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) { System.out.println("前置日志"); Object result = proxy.invokeSuper(obj, args); // 调用父类方法 System.out.println("后置日志"); return result; } } -
生成代理对象
Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Service.class); // 设置父类为目标类 enhancer.setCallback(new LogInterceptor()); // 设置方法拦截器 Service proxy = (Service) enhancer.create(); // 生成代理对象 -
调用代理方法
proxy.process(); // 输出: // 前置日志 // 业务逻辑 // 后置日志
四、关键注意事项
-
final方法无法代理
CGLIB通过继承实现代理,final方法无法被重写,因此无法代理。 -
构造函数限制
代理类默认调用目标类的无参构造函数,若目标类没有无参构造器,需通过Enhancer.create(Class[], Object[])指定参数。 -
性能优化
FastClass机制通过方法索引直接调用目标方法,相比JDK动态代理的反射调用,执行效率更高。
五、与JDK动态代理的本质区别
| 维度 | CGLIB动态代理 | JDK动态代理 |
|---|---|---|
| 实现方式 | 继承目标类,生成子类 | 实现接口,生成接口代理类 |
| 目标要求 | 可代理普通类,无需接口 | 必须实现至少一个接口 |
| 方法覆盖 | 重写非final方法 | 实现接口方法 |
| 性能 | 初始生成慢,执行快(FastClass优化) | 初始生成快,执行慢(反射调用) |
| 适用场景 | 复杂类继承结构、无接口的类 | 简单接口代理、轻量级场景 |
总结
CGLIB动态代理通过运行时生成目标类的子类,重写方法并插入拦截逻辑,使得调用原方法时实际执行的是代理类的增强逻辑。其核心依赖字节码生成技术(ASM)和MethodInterceptor拦截器机制,适用于需要代理普通类或复杂继承结构的场景。

浙公网安备 33010602011771号