保姆级教程】代理模式玩明白了吗?从周杰伦演唱会聊聊静态代理、JDK 动态代理、CGLIB!
本文用「周杰伦开演唱会」的真实场景,把代理模式的 3 种实现讲透,代码可直接运行,文末附对比表,新手也能秒懂!
一、代理模式是个啥?—— 经纪人的 “生存法则”
先问大家一个问题:周杰伦开演唱会时,会自己去和主办方面谈、签合同、订机票、收定金吗?
答案肯定是:不会!周董只需要专心唱歌,剩下的琐事全交给经纪人搞定 —— 而这个 “经纪人替明星处理琐事、控制明星业务访问” 的逻辑,就是编程里的「代理模式」!
1.1 代理模式的核心作用
通过 “代理对象” 控制对 “真实对象” 的访问,在调用真实对象的方法前做前置处理(比如经纪人谈合同)、调用后做后置处理(比如经纪人收尾款),核心是 “增强功能,控制访问”。
1.2 代理模式的三大角色(周杰伦版)
表格
|
角色类型 |
对应场景 |
核心职责 |
|
抽象角色(接口) |
明星业务规范 |
定义明星要做的事(唱歌、面谈等) |
|
真实角色 |
周杰伦本人 |
实现核心业务(只负责唱歌) |
|
代理角色 |
周杰伦的经纪人 |
代理真实角色,处理琐事 + 调用核心业务 |
二、静态代理:专属经纪人,只为周杰伦服务
静态代理就像 “专属经纪人”—— 只服务周杰伦一个人,经纪人和周杰伦都得遵守 “明星业务规范”(实现同一个接口)。
2.1 第一步:定义 “明星业务接口”(抽象角色)
先定规矩:明星要做哪些事?

2.2 第二步:周杰伦本人(真实角色)
周董只干核心活 —— 唱歌,其他事一概不管:

2.3 第三步:专属经纪人(代理角色)
经纪人替周董处理所有琐事,只在 “唱歌” 时喊周董出场:

2.4 第四步:测试 —— 一场演唱会的完整流程

2.5 运行结果

2.6 静态代理的 “槽点”(为啥不够香?)
- 代码重复严重:经纪人(代理类)和周杰伦(实现类)都要实现Star接口,接口方法越多,重复代码越多;
- 通用性差:这个经纪人只服务周杰伦,如果要给 “刘德华”“张学友” 找经纪人,得重新写一套代理类 —— 太麻烦!
三、JDK 动态代理:万能经纪人,能服务所有明星
JDK 动态代理就像 “万能经纪人”—— 不用为每个明星单独写代理类,一套代码能服务所有实现了接口的明星,彻底解决静态代理的痛点!
3.1 第一步:简化接口(抽象角色)
只保留核心业务(唱歌),突出重点:

3.2 第二步:周杰伦依旧只唱歌(真实角色)

3.3 第三步:打造 “万能经纪人工厂”(代理工厂)
通过反射动态生成代理对象,支持所有实现接口的明星:

3.4 第四步:测试 —— 万能经纪人服务周杰伦

3.5 运行结果

3.6 JDK 动态代理的 “小优势”
- 无代码重复:不用和真实角色实现同一个接口,代理逻辑集中在InvocationHandler中;
- 通用性强:一套工厂代码能代理所有实现了接口的对象(换刘德华只需要new ProxyFactory(new RealLiuDeHua()));
- 动态生成:代理类在运行时动态生成,不用手动编写代理类。
四、CGLIB 动态代理:无接口也能代理的 “超级经纪人”
JDK 动态代理有个小缺点 —— 必须要求真实角色实现接口!如果周杰伦 “不想签接口”(没实现任何接口),咋办?
CGLIB 登场!它不用接口,直接生成真实角色的子类作为代理对象,堪称 “超级经纪人”~
4.1 第一步:引入 CGLIB 依赖
如果项目里有 Spring-Core,可直接用(Spring 内置了 CGLIB);否则手动引入:

4.2 第二步:周杰伦不用接接口(真实角色)

4.3 第三步:超级经纪人工厂(CGLIB 代理工厂)

4.4 第四步:测试 —— 无接口也能搞定

4.5 运行结果

4.6 CGLIB 的 “小特点”
- 无需接口:突破 JDK 动态代理的限制,代理任意类(只要不是 final 类);
- 子类代理:代理对象是真实角色的子类,通过继承实现增强;
- Spring 默认选择:Spring 中如果目标对象有接口,用 JDK 动态代理;无接口,用 CGLIB。
五、三大代理模式对比(一张表看懂)
表格
|
特性 |
静态代理 |
JDK 动态代理 |
CGLIB 动态代理 |
|
实现方式 |
实现同一接口 |
实现 InvocationHandler |
继承目标类 + MethodInterceptor |
|
是否需要接口 |
是 |
是 |
否 |
|
代理类创建时机 |
编译期 |
运行期 |
运行期 |
|
通用性 |
差(仅服务一个类) |
强(服务所有接口类) |
强(服务所有非 final 类) |
|
性能 |
高(编译期生成) |
中(反射调用) |
高(直接调用方法) |
六、总结 & 面试小彩蛋
- 代理模式核心:代理对象控制真实对象的访问,增强核心业务的前后逻辑;
- 静态代理:简单易上手,但代码重复、通用性差,适合简单场景;
- JDK 动态代理:基于接口,运行时生成代理类,通用性强,Spring AOP 默认选择(有接口时);
- CGLIB 动态代理:基于继承,无需接口,性能略优,适合无接口的场景;
面试常问:Spring AOP 用了哪种代理?
- 如果目标对象实现了接口:默认用 JDK 动态代理;
- 如果目标对象没实现接口:用 CGLIB 动态代理;
- 也可以手动配置 Spring 强制使用 CGLIB(设置proxy-target-class="true")。
最后
如果这篇用 “周杰伦演唱会” 讲透代理模式的文章对你有帮助,别忘了点赞 + 收藏~关注我,后续解锁更多 “接地气” 的 Java 设计模式教程!
更多推荐



所有评论(0)