CGLIB代理final类或方法会报错,因JVM禁止继承final类和重写final方法;解决方式包括移除final修饰符、改用JDK动态代理、升级到ByteBuddy等现代方案,或临时绕过。

CGLIB 代理 final 类或 final 方法时会直接报错,根本原因不是配置问题,而是 JVM 的硬性限制——final 类不可被继承,final 方法不可被重写。CGLIB 的工作方式是生成目标类的子类并覆写方法,一旦遇到 final,字节码生成阶段就会失败,抛出 IllegalArgumentException: Cannot subclass final class 或类似异常。
移除 final 修饰符(最直接有效)
如果代码由你控制,这是首选方案:
- 将目标类的
final关键字去掉,确保它可被继承 - 把需要被 AOP 拦截的方法也去掉
final(同时确认不是private或static) - Spring 启动后能正常创建 CGLIB 代理,切面逻辑即可生效
改用 JDK 动态代理(需接口支持)
当无法修改类定义(如第三方 final 类),可切换代理机制:
- 为该类提取一个接口,让原类实现它
- 在 Spring 配置中关闭 CGLIB,启用 JDK 代理:
@EnableAspectJAutoProxy(proxyTargetClass = false) - 注入点使用接口类型,AOP 将通过接口代理生效
升级到现代替代方案(面向未来)
CGLIB 在 JDK 17+ 中存在兼容性风险,且官方已停止维护。推荐逐步迁移:
立即学习“Java免费学习笔记(深入)”;
- 用 ByteBuddy 替代:支持运行时字节码增强,对 final 类可通过
redefine或instrumentation实现无侵入拦截 - Spring Framework 6.x / Boot 3.x 已将 CGLIB 设为 fallback 策略,默认优先尝试 JDK 代理
- 结合编译期 AOP(如 AspectJ weaver)或 GraalVM 兼容设计,减少对运行时动态代理的依赖
临时绕过(不推荐长期使用)
仅限紧急排查或测试环境:
- 添加 JVM 参数放宽反射限制(针对 JDK 17+):
--add-opens java.base/java.lang=ALL-UNNAMED - 使用
cglib-nodep版本(如 3.3.0),避免依赖冲突 - 注意:这些不能解决 final 本身的继承限制,只缓解底层反射报错,核心问题仍存在


















