动态代理
约 844 字大约 3 分钟
2025-09-04
动态代理是一种在程序运行时(而非编译时)动态生成代理对象的技术。它允许在不修改原始类的情况下,通过代理对象拦截对目标对象的方法调用,并在调用前后执行自定义逻辑或增强操作。
目前主流的动态代理实现方式主要有两种:JDK 动态代理和 Cglib 动态代理。
JDK 动态代理
JDK 动态代理是 Java 官方提供的一种动态代理方式。
原理
JDK 动态代理在运行时,会为目标对象所实现的接口动态生成一个实现类(即代理类)。这个代理类实现了目标对象的所有接口,并且在接口方法的实现中包含了增强逻辑以及通过反射调用目标对象原始方法的代码。
限制
使用 JDK 动态代理有一个核心限制:目标类必须实现至少一个接口。如果目标类没有实现任何接口,则无法使用 JDK 动态代理。
调用过程
当客户端调用代理对象的方法时,实际上会调用到代理类中对应的方法。在代理类的方法中,会首先执行预设的增强逻辑,然后通过反射机制调用目标对象的原始方法,最后再执行后续的增强逻辑。
Cglib 动态代理
Cglib(Code Generation Library)是一个强大的高性能字节码生成库,它可以在运行时扩展 Java 类和实现 Java 接口。
原理
Cglib 动态代理在运行时,会动态生成目标类的一个子类(即代理类),并重写父类(目标类)的所有非 final 方法,在重写的方法中加入增强代码。Cglib 底层通过 ASM(一个轻量级的字节码处理框架)来转换和生成字节码。
限制
如果目标类是被 final 修饰的,则不能使用 Cglib 代理,因为 final 类不能被继承。同样,如果目标方法是 final 或 private 的,也无法被 Cglib 代理。
调用过程
当客户端调用代理对象的方法时,实际上会调用到 Cglib 生成的子类中重写的方法。在这个重写方法中,会执行增强逻辑,然后直接调用父类(目标类)对应的原始方法。
两种动态代理方式的对比
| 特性 | JDK 动态代理 | Cglib 动态代理 |
|---|---|---|
| 原理 | 基于接口生成代理类 | 基于继承生成代理类(生成目标类的子类) |
| 代理对象生成速度 | 相对较快 | 相对较慢(需要生成新的字节码文件并加载) |
| 方法调用速度 | 涉及到反射调用目标方法,性能开销相对较大 | 直接调用父类方法,性能开销相对较小 |
| 能否代理无接口类 | 不能,目标类必须实现接口 | 能,只要目标类不是 final 的,且方法不是 final |
| 底层技术 | Java 反射 API | ASM 字节码生成框架 |
注
随着 JDK 版本的不断升级,JVM 对反射机制的优化也在持续进行,JDK 动态代理的调用性能已显著提升,在某些场景下甚至可能超越 Cglib。