首页/新闻资讯/正文详情

Spring AOP 底层到底怎么跑的,我翻了一圈源码终于搞明白了

发布时间:2026/9/22 21:28:23 来源:云帆数科 栏目:资讯中心
Spring AOP 底层到底怎么跑的,我翻了一圈源码终于搞明白了
上一篇博客我整理了 AOP 的八个概念算是知道了是什么。但心里一直有个疑问Spring 到底是怎么做到的我在类上加个AspectSpring 就能自动帮我拦截方法了这背后发生了什么这篇就把我查到的东西整理一下尽量用自己能理解的话说。代理对象是怎么来的上一篇说过AOP 的核心是代理。你调的UserService其实不是真正的UserService而是 Spring 给你生成的一个代理对象。那这个代理对象是什么时候、怎么生成的答案是 Spring 容器启动的时候。Spring 里有一个东西叫BeanPostProcessor翻译过来就是 Bean 的后处理器。它的工作是在每个 Bean 创建完成之后检查一下看看这个 Bean 有没有被某个切面匹配到。如果有就不把原始对象放进容器了而是给它生成一个代理对象放进去。所以当你在代码里写Autowired UserService userService的时候Spring 给你的就已经是代理了。你从头到尾都没碰过原始的UserService。那代理对象是怎么生成的这就涉及到两种技术了。两种代理方式JDK 动态代理和 CGLIBSpring 生成代理对象有两种方式取决于目标对象长什么样。第一种JDK 动态代理。这是 Java 自带的用的java.lang.reflect.Proxy这个类。它能在程序运行的时候动态生成一个实现了目标接口的代理类。所有方法调用都会被转发到一个InvocationHandler的invoke方法里你就可以在这里面加通知逻辑。但它有个硬限制目标对象必须实现了接口。因为 JDK 动态代理的原理是实现接口不是继承类。没接口就没法用。第二种CGLIB 字节码增强。CGLIB 用的是一个叫 ASM 的底层框架它能在运行的时候动态生成目标类的子类。代理对象是目标类的儿子重写了父亲的方法。调用的时候通过MethodProxy触发逻辑。因为是基于继承所以不需要接口什么类都能代理。但也有个限制final修饰的类和方法没法被继承和重写所以 CGLIB 对final无能为力。Spring 怎么选如果目标对象实现了接口默认用 JDK 动态代理。没实现接口就自动降级用 CGLIB。不过 Spring Boot 2.x 之后把默认改成了 CGLIB因为 JDK 代理在某些场景下会有坑统一用 CGLIB 更省事。我自己写代码的时候一般不去管它用哪种让 Spring 自己决定就行。知道有这么回事主要是为了遇到代理失效的时候能排查原因。比如你给一个final方法加了切面发现没生效这时候你就知道哦CGLIB 没法重写final方法。Spring AOP 和 AspectJ 的区别运行期织入查资料的时候我发现 AOP 的实现不止 Spring 一种还有一个叫 AspectJ 的东西功能更强。它俩的区别主要在织入的时机上。AspectJ 是编译期或类加载期织入。它有自己的编译器叫ajc在代码编译成.class文件的时候或者类加载到 JVM 的时候直接把切面代码改写到目标类的字节码里。改完之后目标类的.class文件就已经包含切面逻辑了。这种方式性能好因为运行时就是一段普通的代码没有额外的代理开销。但代价是你得换编译器或者配置特殊的 ClassLoader对项目有侵入。Spring AOP 是运行期织入。目标类的源代码和字节码一个字都不动。Spring 在程序跑起来之后在内存中动态生成一个代理对象。你调的是代理代理再去调真正的目标对象。性能上比 AspectJ 稍微差一点点因为多了一层代理转发。但好处是对项目零侵入不需要换编译器不需要改构建流程只要用了 Spring 容器就能直接用。这也是为什么大部分 Spring 项目都用 Spring AOP 而不是 AspectJ。不过如果你需要拦截字段赋值、构造函数这些 Spring AOP 搞不定的场景那就只能上 AspectJ 了。拦截器链多个切面怎么协作实际项目里一个方法上可能叠了好几层切面。比如一个接口既要记日志又要验权限还要管事务。这三个切面都匹配到了同一个方法那它们按什么顺序执行Spring 底层用的是责任链模式。具体过程是这样的所有的通知不管是Before、After还是AroundSpring 都会把它们统一包装成MethodInterceptor接口。然后把匹配到这个方法的所有拦截器排成一条链放在一个MethodInvocation对象里。方法被调用的时候不是直接去执行目标方法而是从链的第一个拦截器开始走。每个拦截器做完自己的前置逻辑之后调用invocation.proceed()把控制权交给下一个拦截器。等所有拦截器都走完了最后才通过反射调用真正的目标方法。目标方法执行完之后调用链又逆序往回走依次触发各个拦截器的后置逻辑。画出来大概是这样假设日志切面在外层事务切面在内层调用代理方法 → 日志拦截器记录开始时间 → 事务拦截器开启事务 → 执行真正的目标方法 ← 事务拦截器提交事务 ← 日志拦截器记录耗时每个拦截器只关心自己的事互相不知道对方的存在。这就是责任链的好处你加一个新切面不需要改已有的任何一个切面。Around 通知的 proceed() 到底在干嘛五种通知里环绕通知Around是最灵活的也是最容易写错的。它的核心就是那个proceed()方法。proceed()做的事情是把控制权交给链中的下一个拦截器或者最终的目标方法。如果你不调proceed()后面的拦截器和目标方法都不会执行。这个特性可以用来做很多事情。比如权限校验如果用户没权限直接不调proceed()方法就被拦住了。但这也意味着如果你忘了调proceed()业务方法永远不会执行而且不会报任何错就是静默失败了。这个坑我踩过一次排查了半天。Around(serviceLayer())publicObjectcheckPermission(ProceedingJoinPointjoinPoint)throwsThrowable{if(!hasPermission()){thrownewRuntimeException(没有权限);}// 如果这里忘了写 proceed()目标方法就永远不会执行returnjoinPoint.proceed();}小结一下Spring AOP 底层其实就做了三件事第一容器启动时扫描所有 Bean看它们有没有被切面匹配到匹配到的就生成代理对象替换掉原始对象。第二生成代理的方式有两种有接口用 JDK 动态代理没接口用 CGLIB。目标类的字节码一个字都不动。第三方法被调用的时候Spring 把匹配到的所有切面包装成拦截器链按顺序依次执行最后才调用目标方法。概念层面看着很抽象但底层拆开看其实都是 Java 的基本功反射、动态代理、责任链模式。搞清楚这几个东西AOP 的原理就没那么玄了。

相关推荐

BiliTools:3步将B站视频变成你的个人知识库,AI智能总结让学习效率提升300%
BiliTools:3步将B站视频变成你的个人知识库,AI智能总结让学习效率提升300%

BiliTools:3步将B站视频变成你的个人知识库,AI智能总结让学习效率提升300% 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_T… · 2026/9/23 18:58:51

四款新开源图像生成模型硬核实测与选型指南
四款新开源图像生成模型硬核实测与选型指南

1. 这不是又一个“跑分榜单”,而是实测四款新锐图像生成模型的硬核拆解 最近两周,朋友圈和几个技术群被 Z-Image-Turbo、Flux.2 Dev、Ovis-Image 和 LongCat-Image 这四个名字反复刷屏。不是因为某家大厂发布了什么重磅更新,而是这四款模型几… · 2026/9/23 6:00:01

如何快速上手ReadCat:免费开源小说阅读器完整使用指南
如何快速上手ReadCat:免费开源小说阅读器完整使用指南

如何快速上手ReadCat:免费开源小说阅读器完整使用指南 【免费下载链接】read-cat 一款免费、开源、简洁、纯净、无广告的小说阅读器 项目地址: https://gitcode.com/gh_mirrors/re/read-cat ReadCat免费开源小说阅读器是一款专注于提供纯净、无干扰阅读体验的… · 2026/9/22 14:11:54

cs1.6 机器人图解原理:3个坑帮你搞定配置
cs1.6 机器人图解原理:3个坑帮你搞定配置

cs1.6 机器人图解原理:3个坑帮你搞定配置 配置环境就卡半天,是不是你的日常?很多人对着 cs1.6 机器人 的插件文档头大,其实核心逻辑很简单。今天咱们不绕弯子,直接上 图解原理 ,把那些晦涩的 Hook… · 2026/9/23 18:58:42

5年老兵揭秘:一文搞懂wwwxxx动漫底层逻辑与手写核心
5年老兵揭秘:一文搞懂wwwxxx动漫底层逻辑与手写核心

5年老兵揭秘:一文搞懂wwwxxx动漫底层逻辑与手写核心 还在为只会写 for 循环,却搞不定一个完整页面而头疼吗?很多开发者卡在“学会语法却不知怎么搭项目”这一步,明明每个知识点都懂,代码一拼就报错。别慌,今天咱们不聊虚的,直接拆解… · 2026/9/23 18:58:36

Java Swing扫雷实战:事件驱动与状态管理深度解析
Java Swing扫雷实战:事件驱动与状态管理深度解析

简介:这是一份基于Java实现的经典Windows扫雷游戏完整源码工程,面向Java初学者与GUI编程入门者,帮助理解事件驱动、二维数组逻辑设计、递归展开算法及Swing界面布局等核心知识点。资源包含56个文件,主体为28个Java源文件&#xff… · 2026/9/23 18:58:29

IronClaw Google Slides 扩展:用 replace_shapes_with_image 将占位形状批量替换为图片
IronClaw Google Slides 扩展:用 replace_shapes_with_image 将占位形状批量替换为图片

人工智能AI 应用交互助手AI Agent 【免费下载链接】ironclaw IronClaw is an Agent OS focused on privacy, security and extensibility 项目地址: https://gitcode.com/gh_mirrors/iro/ironclaw 点击查看 免费下载 在 IronClaw 的 Google Slides 扩展&#xff08… · 2026/9/23 18:58:17

3步搞定整体与部分:后端开发者的保姆级教程
3步搞定整体与部分:后端开发者的保姆级教程

3步搞定整体与部分:后端开发者的保姆级教程 复制来的代码跑不通,报错日志一屏屏往外跳,你盯着屏幕发呆,完全不知道从哪下手调?别急,这种“整体混乱、部分断裂”的情况,在房建工程信息化和后端开发里太常见了。 今天这篇 保姆级教程… · 2026/9/23 18:58:10

打不死的小强:后端高可用架构最佳实践与面试避坑指南
打不死的小强:后端高可用架构最佳实践与面试避坑指南

打不死的小强:后端高可用架构最佳实践与面试避坑指南 配置环境就卡半天,调试服务又超时,这种“打不死的小强”般的故障排查体验,谁还没经历过?在准备后端高级开发或架构师面试时,面试官最爱拿这种“顽固”的系统稳定性问题来考察你的底层功底。今天咱们… · 2026/9/23 18:58:04

3招搞定手机怎么下载微信面试难题实战项目解析
3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧
Win7无线热点配置工具源码解析:解决API失效的3个实战技巧

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧 Win7无线热点配置工具在Win10/11上跑不动?不是你的问题,是版本升级后 API 全变了。很多老项目里的 netsh wlan… · 2026/9/23 0:00:36

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码