从静态代理到动态代理,再到 AOP(一篇彻底讲透)
- 从静态代理到动态代理,再到 AOP(一篇彻底讲透)
- 一、先从一个最简单的业务开始
- 1️⃣ 定义接口
- 2️⃣ 实现类(真正的业务代码)
- 二、什么是代理?(核心思想)
- 三、静态代理(最原始的方式)
- 1️⃣ 手写一个代理类
- 2️⃣ 使用代理
- 3️⃣ 执行结果
- 四、静态代理的问题(非常致命)
- 五、动态代理登场:代理类让 JVM 帮你生成
- 六、JDK 动态代理(最常见)
- ⚠️ 前提条件
- 1️⃣ InvocationHandler(代理的核心)
- 2️⃣ 创建代理对象
- 3️⃣ 执行流程(非常重要)
- 七、动态代理解决了什么?
- 八、动态代理的痛点
- 九、AOP 是什么?
- 十、AOP 写法(你最熟悉的样子)
- 1️⃣ 业务类(完全不关心代理)
- 2️⃣ 切面类
- 3️⃣ 效果
- 十一、AOP 和动态代理的真实关系(重点)
- 十二、一句话总结(建议背下来)
- 十三、真实开发怎么选?
- 结尾
从静态代理到动态代理,再到 AOP(一篇彻底讲透)
很多人在学 Spring AOP 的时候会觉得:
“这不就是魔法吗?
为什么加个@Before,方法就被拦截了?”
其实一点都不魔法。
AOP 的本质,就是代理。
这篇文章我们从最原始的静态代理开始,一步步走到动态代理,最后你会发现:
👉AOP 只是把动态代理“包装”得更好用了。
一、先从一个最简单的业务开始
1️⃣ 定义接口
publicinterfaceUserService{voidregister();}2️⃣ 实现类(真正的业务代码)
publicclassUserServiceImplimplementsUserService{@Overridepublicvoidregister(){System.out.println("注册用户");}}二、什么是代理?(核心思想)
代理 = 不改原类,在方法前后加逻辑
比如我们想在register()前后加日志:
- 不想改
UserServiceImpl - 不想每个方法都手写日志
三、静态代理(最原始的方式)
1️⃣ 手写一个代理类
publicclassUserServiceProxyimplementsUserService{privateUserServicetarget;publicUserServiceProxy(UserServicetarget){this.target=target;}@Overridepublicvoidregister(){System.out.println("【前置】记录日志");target.register();System.out.println("【后置】结束日志");}}2️⃣ 使用代理
publicclassTest{publicstaticvoidmain(String[]args){UserServicetarget=newUserServiceImpl();UserServiceproxy=newUserServiceProxy(target);proxy.register();}}3️⃣ 执行结果
【前置】记录日志 注册用户 【后置】结束日志四、静态代理的问题(非常致命)
假设你现在有:
- UserService
- OrderService
- ProductService
每个都要:
- 日志
- 权限
- 事务
那你要写多少个代理类?
❌类爆炸
❌大量重复代码
❌维护成本极高
五、动态代理登场:代理类让 JVM 帮你生成
核心思想:
“代理类我不写了,运行时自动生成。”
六、JDK 动态代理(最常见)
⚠️ 前提条件
目标类必须有接口
1️⃣ InvocationHandler(代理的核心)
importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;publicclassLogInvocationHandlerimplementsInvocationHandler{privateObjecttarget;publicLogInvocationHandler(Objecttarget){this.target=target;}@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{System.out.println("【前置】记录日志");Objectresult=method.invoke(target,args);System.out.println("【后置】结束日志");returnresult;}}👉所有方法,都会走 invoke()
2️⃣ 创建代理对象
importjava.lang.reflect.Proxy;publicclassTest{publicstaticvoidmain(String[]args){UserServicetarget=newUserServiceImpl();UserServiceproxy=(UserService)Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),newLogInvocationHandler(target));proxy.register();}}3️⃣ 执行流程(非常重要)
proxy.register() ↓ JVM 自动生成的代理类 ↓ InvocationHandler.invoke() ↓ 前置逻辑 ↓ 真实方法执行 ↓ 后置逻辑👉你没写代理类,但 JVM 帮你写了
七、动态代理解决了什么?
✅ 不用手写代理类
✅ 一套逻辑代理所有方法
✅ 横切逻辑高度复用
但问题也来了 👇
八、动态代理的痛点
Proxy.newProxyInstance(...)InvocationHandler.invoke(...)Method.invoke(...)❌ 写法复杂
❌ 可读性差
❌ 每个项目都要重复造轮子
于是就出现了 ——AOP
九、AOP 是什么?
AOP(面向切面编程)是一种思想
本质仍然是代理
它帮你做了三件事:
- 自动创建代理对象
- 自动决定“代理哪些方法”
- 自动管理生命周期
十、AOP 写法(你最熟悉的样子)
1️⃣ 业务类(完全不关心代理)
@ServicepublicclassUserService{publicvoidregister(){System.out.println("注册用户");}}2️⃣ 切面类
@Aspect@ComponentpublicclassLoggingAspect{@Before("execution(* com.example.UserService.*(..))")publicvoidbefore(){System.out.println("【前置】记录日志");}@AfterReturning("execution(* com.example.UserService.*(..))")publicvoidafter(){System.out.println("【后置】结束日志");}}3️⃣ 效果
【前置】记录日志 注册用户 【后置】结束日志十一、AOP 和动态代理的真实关系(重点)
| 对比 | 动态代理 | AOP |
|---|---|---|
| 是什么 | 技术手段 | 编程思想 + 框架 |
| 是否手写 | 是 | ❌ |
| 使用难度 | 高 | 低 |
| 底层 | 反射 / 字节码 | 动态代理 / CGLIB |
👉Spring AOP 底层,仍然是动态代理
十二、一句话总结(建议背下来)
静态代理:我自己写代理类
动态代理:JVM 帮我写代理类
AOP:我只写规则,代理交给框架
十三、真实开发怎么选?
✅写业务 → 直接用 AOP
✅学原理 / 写框架 → 学动态代理
结尾
当你理解了:
- 静态代理在干嘛
- 动态代理解决了什么
- AOP 封装了哪些细节
你就会发现:
AOP 从来不是魔法,它只是“代理的高级用法”。