博主社群介绍: ① 群内初中生、高中生、本科生、研究生、博士生遍布,可互相学习,交流困惑。
② 热榜top10的常客也在群里,也有数不清的万粉大佬,可以交流写作技巧,上榜经验,涨粉秘籍。
③ 群内也有职场精英,大厂大佬,跨国企业主管,可交流技术、面试、找工作的经验。
进群免费赠送写作秘籍一份,助你由写作小白晋升为创作大佬,进群赠送CSDN评论防封脚本,送真活跃粉丝,助你提升文章热度。
群公告里还有全网大赛约稿汇总/博客提效工具集/CSDN自动化运营脚本 有兴趣的加文末联系方式,备注自己的CSDN昵称,拉你进群,互相学习共同进步。
文章目录
- [Spring Boot AOP(二) 代理机制解析](#Spring Boot AOP(二) 代理机制解析)
-
- [1. 代理机制概述](#1. 代理机制概述)
- [2. JDK 动态代理源码解析](#2. JDK 动态代理源码解析)
- [3. CGLIB 代理源码解析](#3. CGLIB 代理源码解析)
- [4. Spring AOP 代理选择机制](#4. Spring AOP 代理选择机制)
-
- [Mermaid 流程:代理选择逻辑](#Mermaid 流程:代理选择逻辑)
- [5. Spring 代理生成核心源码解析](#5. Spring 代理生成核心源码解析)
-
- [5.1 入口类](#5.1 入口类)
- [5.2 ProxyFactory 核心方法](#5.2 ProxyFactory 核心方法)
- [6. 方法调用链源码解析](#6. 方法调用链源码解析)
- [7. 实战示例:多切面组合](#7. 实战示例:多切面组合)
- [8. 总结](#8. 总结)
- 结束语

Spring Boot AOP(二) 代理机制解析
1. 代理机制概述
Spring AOP 的核心在于 代理对象 ,它负责在方法调用前后织入切面逻辑。Spring AOP 默认只对 Spring 管理的 Bean 生效,并且使用 运行时动态代理(JDK 动态代理或 CGLIB 代理)。
| 代理类型 | 特点 | 使用场景 | 限制 |
|---|---|---|---|
| JDK 动态代理 | 基于接口生成代理对象 | Bean 实现接口 | 只能代理接口方法 |
| CGLIB 代理 | 基于子类生成代理对象 | Bean 无接口或 proxyTargetClass=true | final 类或 final 方法无法代理 |
| ByteBuddy(Spring 5 可选) | 生成字节码动态代理 | 高级场景 | 复杂配置,可替代 CGLIB |
Spring Boot 默认自动选择 JDK 或 CGLIB,除非手动配置
proxyTargetClass=true强制使用 CGLIB。
2. JDK 动态代理源码解析
JDK 动态代理基于 java.lang.reflect.Proxy 和 InvocationHandler 实现。
核心类和方法
java
Object proxy = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
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;
}
}
);
流程示意
客户端调用代理对象方法 InvocationHandler.invoke 切面前置逻辑 调用目标对象方法 切面返回/异常逻辑 返回调用方
特点
- 代理对象和目标对象实现相同接口
- 方法调用通过
InvocationHandler转发 - 执行链由多个
Advice组合而成
3. CGLIB 代理源码解析
CGLIB(Code Generation Library)通过 生成目标类的子类,在方法调用中织入切面逻辑。
核心类
Enhancer:创建代理类MethodInterceptor:拦截方法调用CallbackFilter:控制哪些方法需要拦截
java
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(TargetClass.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("方法调用前");
Object result = proxy.invokeSuper(obj, args);
System.out.println("方法调用后");
return result;
}
});
TargetClass proxy = (TargetClass) enhancer.create();
调用流程
特点
- 生成目标类子类,支持无接口类
- 不能代理 final 类或 final 方法
- 方法调用速度略快于 JDK 动态代理
4. Spring AOP 代理选择机制
Spring 自动选择代理类型:
| 条件 | 结果 |
|---|---|
| Bean 实现接口且 proxyTargetClass=false | 使用 JDK 动态代理 |
| Bean 无接口或 proxyTargetClass=true | 使用 CGLIB 代理 |
java
@EnableAspectJAutoProxy(proxyTargetClass = true) // 强制使用 CGLIB
Mermaid 流程:代理选择逻辑
是 是 否 否 创建 Bean 代理 Bean 实现接口? proxyTargetClass=true? 使用 CGLIB 代理 使用 JDK 代理
5. Spring 代理生成核心源码解析
5.1 入口类
AnnotationAwareAspectJAutoProxyCreator(AOP 自动代理器)负责:
- 扫描 Bean,判断是否匹配切面
- 生成 Advisor(切入点 + 通知)
- 根据条件选择代理类型
- 使用
ProxyFactory或Enhancer创建代理对象
是 否 BeanPostProcessor.postProcessAfterInitialization 是否匹配切面? 创建 ProxyFactory 选择代理类型 JDK/CGLIB 生成代理对象 替换原 Bean 注入容器 直接返回 Bean
5.2 ProxyFactory 核心方法
java
protected Object createProxy(BeanFactory beanFactory, Object target, String beanName) {
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvisors(this.findAdvisors(beanFactory, beanName));
return proxyFactory.getProxy(getProxyClassLoader());
}
6. 方法调用链源码解析
Spring AOP 方法调用链(以 JDK/CGLIB 统一):
- 客户端调用代理对象方法
ReflectiveMethodInvocation封装调用信息- 执行 Advisor 链:
- MethodBeforeAdvice → AroundAdvice → AfterReturning/AfterThrowing
- 最终调用目标方法
- 返回结果或异常传递给代理
客户端调用代理方法 ReflectiveMethodInvocation.proceed Advisor 链: MethodBeforeAdvice Advisor 链: AroundAdvice 调用目标方法 Advisor 链: AfterReturning/AfterThrowing 返回客户端
7. 实战示例:多切面组合
java
@Aspect
@Component
@Order(1)
public class LoggingAspect {
@Before("execution(* com.example.service..*.*(..))")
public void logBefore(JoinPoint jp) {
System.out.println("日志切面前置通知: " + jp.getSignature());
}
}
@Aspect
@Component
@Order(2)
public class PerformanceAspect {
@Around("execution(* com.example.service..*.*(..))")
public Object measureTime(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object result = pjp.proceed();
System.out.println("性能切面耗时: " + (System.currentTimeMillis() - start) + "ms");
return result;
}
}
多切面调用顺序示意
8. 总结
- Spring AOP 核心是 代理对象
- JDK 动态代理针对接口,CGLIB 针对类
- Spring 自动选择代理类型,可配置
proxyTargetClass AnnotationAwareAspectJAutoProxyCreator+ProxyFactory是生成代理的核心- 方法调用链由
Advisor链统一管理,实现通知执行顺序 - Mermaid 流程图直观展示代理生成和方法调用链
结束语

👨💻 关于我
持续学习 | 追求真我
如果本篇文章帮到了你 不妨点个赞吧~ 我会很高兴的。想看更多 那就点个关注吧 我会尽力带来有趣的内容 😎。
感谢订阅专栏 三连文章

掘金点击访问Qiuner CSDN点击访问Qiuner GitHub点击访问Qiuner Gitee点击访问Qiuner
| 专栏 | 简介 |
|---|---|
| 📊 一图读懂系列 | 图文并茂,轻松理解复杂概念 |
| 📝 一文读懂系列 | 深入浅出,全面解析技术要点 |
| 🌟持续更新 | 保持学习,不断进步 |
| 🎯 人生经验 | 经验分享,共同成长 |
你好,我是Qiuner. 为帮助别人少走弯路而写博客
如果本篇文章帮到了你 不妨点个赞 吧~ 我会很高兴的 😄 (^ ~ ^) 。想看更多 那就点个关注吧 我会尽力带来有趣的内容 😎。
代码都在Github或Gitee上,如有需要可以去上面自行下载。记得给我点星星哦😍
如果你遇到了问题,自己没法解决,可以去我掘金评论区问。CSDN评论区和私信消息看不完 掘金消息少一点.
| 上一篇推荐 | 链接 |
|---|---|
| Java程序员快又扎实的学习路线 | 点击该处自动跳转查看哦 |
| 一文读懂 AI | 点击该处自动跳转查看哦 |
| 一文读懂 服务器 | 点击该处自动跳转查看哦 |
| 2024年创作回顾 | 点击该处自动跳转查看哦 |
| 一文读懂 ESLint配置 | 点击该处自动跳转查看哦 |
| 老鸟如何追求快捷操作电脑 | 点击该处自动跳转查看哦 |
| 未来会写什么文章? | 预告链接 |
|---|---|
| 一文读懂 XX? | 点击该处自动跳转查看哦 |
| 2025年终总结 | 点击该处自动跳转查看哦 |
| 一图读懂 XX? | 点击该处自动跳转查看哦 |

关于"掰开揉碎讲编程"系列
编程的世界常常让初学者望而生畏------晦涩的术语、抽象的概念、复杂的原理,像是一座座难以逾越的高山。但学习编程,本不该如此艰难。
"掰开揉碎讲编程"系列的初衷,就是把那些看似高深的技术知识,像掰开面包一样拆解开来,像揉碎面团一样细细讲透。这里不玩虚的,不堆砌术语,只用最朴实的语言、最贴近生活的比喻,再搭配手绘般的图解示意。抽象的概念画出来,复杂的流程拆开看,让编程知识变得像看图说话一样简单。
与其他基础教程不同的是,我不会上来就告诉你"怎么装、怎么用"。每一个工具、每一项技术,我都会带你了解它的前世今生------它诞生的背景、要解决的痛点、在整个开发流程中的位置。只有理解了"为什么需要它",才能真正掌握"如何用好它"。
内容上,这个系列会有两种文章:
一种是长篇深度文,慢工出细活,把一个技术从头到尾讲清楚------它怎么来的、为什么重要、怎么用、怎么用好。适合系统学习,打牢基础。
另一种是短篇问题文,专治各种疑难杂症------IDEA汉化后乱码了、Git冲突不知道怎么解、环境变量配置出了岔子等等。遇到问题时翻一翻,快速解决,继续开发。
这里没有"懂的都懂"式的敷衍,没有"显而易见"的跳跃,每一个概念都会从零开始构建,每一处难点都会反复推敲。就像老师傅手把手教徒弟,我想做的,是让每一个想学编程的人,都能真正理解技术背后的本质。
无论你是刚接触编程的萌新,还是想要夯实基础的开发者,这个系列都希望成为你的良师益友。让我们一起,把编程这件事,掰开了、揉碎了,彻彻底底搞明白。