🔍 一、什么是动态代理?
动态代理就是在运行时,动态生成一个代理类,来“代理”你原本的对象,并添加一些额外逻辑。
相比静态代理(你手动写一个代理类),动态代理是自动帮你生成的!
🧱 二、动态代理的两种方式
技术 | 依赖 | 要求 | 原理 |
---|---|---|---|
JDK 动态代理 | Java 原生 API | 目标类必须实现接口 | 使用 java.lang.reflect.Proxy 创建代理对象 |
CGLIB 动态代理 | 第三方库(Spring 内置) | 没有接口也可以 | 通过继承目标类 + 字节码技术生成代理子类 |
✅ 三、JDK 动态代理详解
1. 定义一个接口 + 实现类
public interface UserService {
void addUser();
}
public class UserServiceImpl implements UserService {
public void addUser() {
System.out.println("添加用户");
}
}
2. 写一个 InvocationHandler
这个类定义了你增强的逻辑:
import java.lang.reflect.*;
public class LogHandler implements InvocationHandler {
private Object target;
public LogHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法调用前记录日志...");
Object result = method.invoke(target, args);
System.out.println("方法调用后记录日志...");
return result;
}
}
3. 使用 Proxy 创建代理对象
UserService target = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new LogHandler(target)
);
proxy.addUser(); // 实际执行的是代理逻辑!
⚙️ 四、JDK 动态代理底层原理
-
JVM 运行时生成一个代理类
$Proxy0
-
这个类实现了你给的接口(UserService)
-
所有方法调用都会被转发给
InvocationHandler.invoke()
-
你在 invoke() 中决定:怎么处理这个方法
💡 五、CGLIB 动态代理简介(Spring AOP 用得很多)
如果你没有接口,JDK 代理就失效了,这时用 CGLIB:
-
它会生成一个目标类的子类,重写所有非 final 方法
-
然后在重写方法中加入你要增强的逻辑
Spring 默认使用 CGLIB,如果目标类没有接口。
📌 六、动态代理 vs 静态代理
对比项 | 静态代理 | 动态代理 |
---|---|---|
编写方式 | 手动写代理类 | 运行时自动生成 |
灵活性 | 低,每个类都要写一次代理 | 高,通用 InvocationHandler |
接口要求 | 无 | JDK 要求必须有接口;CGLIB 无要求 |
性能 | 稍好一点(但不明显) | 稍慢,需反射或字节码处理 |
Spring AOP 默认使用 | 否 | 是 |
🎯 七、动态代理的应用场景
-
Spring AOP(日志、权限、事务等)
-
RPC 框架(如 Dubbo)
-
ORM 框架(如 MyBatis Mapper)
-
拦截器机制
-
接口适配、Mock 测试等
🧠 总结一句话:
动态代理就是:你不用写代理类,Java 或 CGLIB 会帮你生成一个“假装是你”的对象,并在方法执行前后“做点别的事”。