描述动态代理的几种实现方式,分别说明优缺点¶
一、动态代理是什么¶
在运行时生成代理类,不写死代理代码。AOP、RPC 都基于它。
二、JDK 动态代理¶
原理¶
基于接口,用 java.lang.reflect.Proxy 生成实现类。
interface UserService {
void save();
}
class UserServiceImpl implements UserService {
public void save() { System.out.println("save"); }
}
UserService proxy = (UserService) Proxy.newProxyInstance(
classLoader,
new Class[]{UserService.class},
(p, method, args) -> {
System.out.println("before");
Object r = method.invoke(new UserServiceImpl(), args);
System.out.println("after");
return r;
}
);
proxy.save();
优缺点¶
- ✅ 不需要第三方库,JDK 自带。
- ✅ 接口改了不用重新生成代理。
- ❌ 只能代理接口,不能代理类。
三、CGLIB 动态代理¶
原理¶
基于继承,用 ASM 生成目标类的子类,重写方法。
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserServiceImpl.class);
enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
System.out.println("before");
Object r = proxy.invokeSuper(obj, args);
System.out.println("after");
return r;
});
UserService proxy = (UserService) enhancer.create();
优缺点¶
- ✅ 可以代理类,不需要接口。
- ✅ 性能比 JDK 动态代理高(FastClass 机制)。
- ❌ 不能代理 final 类/方法(不能继承)。
- ❌ 第三方依赖。
四、对比¶
| JDK 动态代理 | CGLIB | |
|---|---|---|
| 基础 | 接口 | 继承子类 |
| 要求 | 目标类实现接口 | 目标类非 final |
| 性能 | 创建快,调用慢 | 创建慢,调用快 |
| Spring 默认 | 有接口用 JDK | Spring Boot 2.x 默认 CGLIB |
五、其他方式¶
Javassist¶
JBoss 用,API 比 ASM 友好,性能中等。
ASM / ByteBuddy¶
底层字节码操作,性能最高,学习曲线陡。
高频追问
- 为什么 CGLIB 不能代理 final?因为它生成子类。
- Spring AOP 怎么选?有接口用 JDK 动态代理,没有接口用 CGLIB。