CGLIB无法代理接口,因其通过生成子类实现代理,而Java中接口不可继承;它仅能代理非final的普通类,且要求构造器可见、无模块封装限制。

CGLIB 无法“补齐接口限制”——它根本不管接口,只代理类;想代理接口请用 JDK 动态代理,想代理没有接口的类才轮到 CGLIB。
为什么 CGLIB 代理不了接口?
CGLIB 的核心是字节码增强:在运行时生成目标类的子类,重写其非 final 方法并插入拦截逻辑。它不依赖接口,也不需要目标实现任何接口——这恰恰是它的优势,也是它的边界。
如果你的目标对象实现了接口,但你仍强行用 CGLIB 去代理它,CGLIB 会忽略接口,只关注类本身;而如果目标只有接口、没有具体类(比如纯 interface 类型变量),CGLIB 根本无从下手,会直接抛出 IllegalArgumentException: Cannot subclass interface。
- 接口不能被继承(Java 语法限制),
Enhancer创建子类时遇到接口会失败 - CGLIB 的
setSuperclass()必须传入Class,且不能是接口类型 - 即使你传了接口的
Class对象,create()会立即报错,不会静默降级
如何正确使用 CGLIB 代理一个无接口的类?
典型场景:你有一个工具类 OrderService,没实现任何接口,但你想记录所有方法执行耗时。这时 CGLIB 是合理选择。
关键步骤:
- 引入依赖:
cglib-nodep(避免 ASM 版本冲突) - 创建
Enhancer实例,调用setSuperclass(OrderService.class) - 设置
setCallback(),通常用MethodInterceptor实现逻辑织入 - 确保目标类和方法不是
final(否则 CGLIB 无法重写) - 调用
create()得到子类实例,它与原类类型兼容(可强转为OrderService)
示例片段:
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OrderService.class);
enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
long start = System.nanoTime();
Object result = proxy.invokeSuper(obj, args);
System.out.println(method + " took " + (System.nanoTime() - start));
return result;
});
OrderService proxy = (OrderService) enhancer.create(); // 成功返回子类实例
CGLIB vs JDK 动态代理:选错就卡死
这不是风格偏好问题,而是类型系统层面的硬约束:
- JDK 代理只能代理
interface,返回的是接口类型实例;目标若无接口,JDK 代理直接不可用 - CGLIB 只能代理
class,且要求类可被继承(非final)、构造器可访问(不能是 private) - 两者不互斥,但也不能混用:Spring AOP 默认优先用 JDK(有接口时),回退才用 CGLIB;手动选型必须明确目标类型
- 性能上 CGLIB 创建代理稍慢(生成字节码),但调用开销略低于 JDK(无反射调用);不过差异在纳秒级,别过早优化
常见误判点:new ArrayList() 能被 CGLIB 代理吗?不能——ArrayList 是 final 类,CGLIB 会抛 IllegalArgumentException: Cannot subclass final class。
final 方法、private 构造器、模块封装都会让 CGLIB 失效
这些不是配置问题,是 JVM 层面的限制,CGLIB 无法绕过:
-
final方法不会被重写,拦截器对它完全无效——日志、事务、重试等逻辑全部跳过 - 若目标类只有
private构造器,CGLIB 无法实例化子类,create()抛IllegalStateException: No visible constructors - JDK 9+ 模块系统下,若目标类所在模块未对
net.sf.cglib开放包(opens或exports),字节码生成会失败,报Module not open to cglib - 使用 Lombok 的
@RequiredArgsConstructor且字段全final时,可能意外生成private构造器,导致 CGLIB 失败
真正要“补齐接口限制”的路只有一条:给类加接口,然后切回 JDK 代理;或者接受 CGLIB 的能力边界——它不补接口,它绕开接口。

















