根本原因是目标类或方法被final修饰导致CGLIB无法继承生成子类,抛出IllegalArgumentException;需移除final、private、static修饰,并正确配置Enhancer的setSuperclass和setCallback,调用proxy.invokeSuper而非method.invoke。

为什么 MethodInterceptor 代理后方法不执行?
根本原因通常是目标类或方法被 final 修饰,CGLIB 无法生成子类覆盖。CGLIB 基于继承实现代理,遇到 final class 或 final method 会直接抛 IllegalArgumentException,而不是静默失败。
- 检查被代理类是否加了
final—— 必须去掉 - 确认方法没被
private或static修饰(CGLIB 不支持) - 若用 Spring,注意
@EnableAspectJAutoProxy(proxyTargetClass = true)才启用 CGLIB,否则默认 JDK 动态代理(只代理接口) - 常见错误现象:
java.lang.IllegalArgumentException: Cannot subclass final class com.example.ServiceImpl
如何正确配置 Enhancer 并设置 MethodInterceptor?
Enhancer 是 CGLIB 的核心入口,但它的链式调用容易漏掉关键步骤:必须显式指定父类(setSuperclass)和回调(setCallback),且 create() 不能带参数除非已定义构造器匹配。
-
enhancer.setSuperclass(YourClass.class)—— 必须,不能是Object.class或接口 -
enhancer.setCallback(new MethodInterceptor() { ... })—— 回调对象必须实现intercept(),且内部要调用method.invokeSuper()(不是method.invoke()) - 如果目标类有带参构造器,需用
enhancer.setCallbacks(...)+enhancer.setCallbackFilter(...)配合,否则create()报NoClassDefFoundError - 示例关键片段:
Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Service.class); enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> { System.out.println("before"); Object result = proxy.invokeSuper(obj, args); // 注意是 invokeSuper System.out.println("after"); return result; }); Service proxy = (Service) enhancer.create();
CGLIB 代理与 JDK 动态代理的兼容性差异
两者机制不同,导致行为差异明显:CGLIB 代理的是类,JDK 代理的是接口。一旦混用(比如 Spring 中部分 Bean 走 JDK、部分走 CGLIB),就容易出现类型转换失败或 AOP 失效。
- 代理对象类型:CGLIB 返回的是子类实例(如
ServiceImpl$$EnhancerByCGLIB$$123456),instanceof ServiceImpl为true;JDK 返回的是接口实现,instanceof ServiceImpl为false - 性能上,CGLIB 首次生成字节码较慢(缓存后无感),但方法调用开销略高于 JDK 代理(多一次
invokeSuper跳转) - Spring 默认策略:有接口 → JDK 代理;无接口 → CGLIB。可通过
spring.aop.proxy-target-class=true强制统一为 CGLIB - 注意:CGLIB 依赖
net.sf.cglib:cglib,而 Spring 5.0+ 已内置org.springframework:spring-core中的精简版,无需额外引包,但版本不匹配仍可能报NoSuchMethodError
字节码增强后常见的运行时异常
CGLIB 在运行时生成类,出错往往在类加载阶段,堆栈信息短、定位难。最常踩的坑是类路径污染或 ASM 版本冲突。
立即学习“Java免费学习笔记(深入)”;
-
java.lang.VerifyError: Expecting a stackmap frame—— 多见于 Java 8+ 使用旧版 CGLIB(cglib-nodep:3.3.0 或更高 -
java.lang.NoClassDefFoundError: org/objectweb/asm/Type—— 表明 ASM 缺失或版本不兼容,CGLIB 3.x 依赖 ASM 7+,别混入 ASM 5.x 的 jar - 使用 Lombok 的
@AllArgsConstructor或@RequiredArgsConstructor时,CGLIB 可能因找不到匹配构造器而失败,建议显式定义无参构造器 - 代理 Spring 管理的 Bean 时,若该 Bean 被
@Transactional或@Async修饰,确保代理类能被 Spring 容器识别(避免手动 newEnhancer())










