jdk动态代理仅支持接口代理,因其实现依赖proxy和invocationhandler生成接口实现类,无法代理无接口的类;cglib通过继承实现代理,要求类与方法非final,且不代理static/private方法。

JDK动态代理只能代理接口,不是类
因为JDK动态代理底层靠 java.lang.reflect.Proxy 和 InvocationHandler 实现,它在运行时生成一个实现目标接口的新类(比如 $Proxy0),但无法为没有接口的类生成代理。如果你试图对一个只有具体类、没实现任何接口的对象做JDK代理,会直接抛出 IllegalArgumentException: target class is not an interface。
实操建议:
立即学习“Java免费学习笔记(深入)”;
本文档主要讲述的是Matlab语言的特点;Matlab具有用法简单、灵活、程式结构性强、延展性好等优点,已经逐渐成为科技计算、视图交互系统和程序中的首选语言工具。特别是它在线性代数、数理统计、自动控制、数字信号处理、动态系统仿真等方面表现突出,已经成为科研工作人员和工程技术人员进行科学研究和生产实践的有利武器。希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
- 确认被代理对象是否实现了至少一个接口;没接口就别硬用JDK代理
- 如果必须代理类(比如第三方库的 final 类或无源码类),立刻转向 CGLIB
- Spring AOP 默认优先用JDK代理,但只要目标类没接口,它会自动 fallback 到 CGLIB——这点容易被忽略,以为配置了
proxy-target-class="false"就一定走JDK,其实 Spring 会自己“违约”
CGLIB代理要求类不能是final,方法也不能是final
CGLIB通过继承目标类生成子类来实现代理,所以它需要能重写目标类的方法。一旦类被声明为 final,或者某个方法是 final,CGLIB在生成子类时就会失败,抛出类似 java.lang.IllegalArgumentException: Cannot subclass final class xxx 或 Method is not public(因为 private/final 方法不可覆写)。
实操建议:
立即学习“Java免费学习笔记(深入)”;
- 检查你要代理的类和关键方法,去掉
final修饰符是最直接的解法 - 如果类来自外部 jar 且无法修改,考虑用 JDK 接口代理 + 包装器模式兜底,而不是强行 CGLIB
- CGLIB 默认不代理
static或private方法,这点和 JDK 代理一致,但新手常误以为“能代理类=能代理所有方法”
InvocationHandler 和 MethodInterceptor 的拦截逻辑差异
JDK 的 InvocationHandler.invoke() 是一次性接收方法调用,返回值由你决定;CGLIB 的 MethodInterceptor.intercept() 多了一个 MethodProxy 参数,它封装了对父类方法的快速调用(methodProxy.invokeSuper()),比反射快,但必须用它才能真正触发原方法执行。
常见错误现象:
- 在 CGLIB 的
intercept()里直接写method.invoke(obj, args)—— 这会绕过 CGLIB 的优化,甚至引发无限递归(因为obj就是代理子类实例) - 忘记调用
methodProxy.invokeSuper(),导致原方法完全不执行,静默失效 - JDK 中
invoke()的proxy参数是代理对象本身,而 CGLIB 的obj是目标类实例(非代理),别混淆用途
性能与字节码兼容性:JDK快在启动,CGLIB快在运行
JDK代理生成类极快(基于已有的 Proxy 模板),但每次方法调用都要走反射(Method.invoke()),开销略高;CGLIB首次生成子类较慢(要解析字节码、生成新类),但后续调用是直接 invokevirtual,几乎无额外成本。
影响点:
- 高频调用场景(如 RPC 拦截、日志埋点),CGLIB 实际吞吐更高
- 应用启动阶段大量创建代理(如 Spring 初始化上百个 Bean),JDK 更轻量,CGLIB 可能拖慢启动速度
- CGLIB 依赖
asm库,不同 JDK 版本下需匹配对应版本(例如 JDK 17+ 要用 asm 9.2+),否则报UnsupportedClassVersionError或java.lang.NoClassDefFoundError: org/objectweb/asm/ClassVisitor
真实项目里,JDK 和 CGLIB 往往共存,选哪个不只看“能不能”,更要看“谁在哪儿卡得最疼”。比如一个接口有 5 个实现类,其中 4 个有接口、1 个没接口还带 final 方法——这时候混合策略比强行统一更稳。









