jdk动态代理只能代理接口,不能代理普通类,因其生成的代理类需继承proxy且实现接口,而java不支持多重继承;cglib通过继承目标类并重写方法实现代理,适用于无接口的普通类。

Java 中无法直接对普通类(非接口)使用 JDK 动态代理,因为 java.lang.reflect.Proxy 只支持代理接口。要代理普通类(即有具体实现的 class),必须借助字节码增强技术,最常用的是 CGLIB。
为什么 JDK 动态代理不能代理普通类?
JDK 动态代理基于接口在运行时生成一个代理类(如 $Proxy0),该类继承自 Proxy 并实现目标接口。而 Java 不支持多重继承,所以它无法同时继承你自己的类和 Proxy 类——因此只能代理接口,不能代理具体类。
用 CGLIB 代理普通类(推荐方式)
CGLIB(Code Generation Library)通过继承目标类、重写其方法来实现代理,适用于没有接口的普通类。需添加依赖:
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
示例:代理一个普通类 UserService
- 定义目标类(无接口):
public class UserService {
public String getName() { return "Alice"; }
public void save(String data) { System.out.println("Saved: " + data); }
}
- 编写 CGLIB 代理逻辑:
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class UserServiceProxy implements MethodInterceptor {
private final UserService target = new UserService();
public UserService getProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(this);
return (UserService) enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before " + method.getName());
Object result = proxy.invokeSuper(obj, args); // 注意:调用父类(target)方法用 invokeSuper
System.out.println("After " + method.getName());
return result;
}
}
- 使用代理:
UserService proxy = new UserServiceProxy().getProxy();
proxy.getName(); // 输出 Before getName → Alice → After getName
proxy.save("test"); // 同理
注意事项与限制
- 目标类不能是 final:CGLIB 通过生成子类实现代理,final 类无法被继承
- 方法不能是 final 或 private:否则无法被重写/拦截
-
构造器参数需匹配:若目标类只有带参构造,需用
enhancer.setCallbacks()+enhancer.setConstructorArgs()配合 - Spring AOP 默认优先用 JDK 代理(有接口时),无接口时自动 fallback 到 CGLIB(需开启
@EnableAspectJAutoProxy(proxyTargetClass = true))
替代方案:Java Agent / Byte Buddy(进阶)
如需更灵活控制(如不修改源码、代理 final 类、或在类加载时织入),可考虑:
- Byte Buddy:现代、API 更友好的字节码库,支持更多场景(包括 mock final 类)
- Java Agent + Instrumentation:在类加载阶段重写字节码,适合监控、APM 等全局代理场景
日常开发中,CGLIB 已足够覆盖绝大多数普通类代理需求;若项目已用 Spring,直接配置 proxyTargetClass = true 即可透明启用 CGLIB 代理。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










