Spring Boot AOP(三) 通知执行链源码解析

复制代码
博主社群介绍: ① 群内初中生、高中生、本科生、研究生、博士生遍布,可互相学习,交流困惑。
② 热榜top10的常客也在群里,也有数不清的万粉大佬,可以交流写作技巧,上榜经验,涨粉秘籍。
③ 群内也有职场精英,大厂大佬,跨国企业主管,可交流技术、面试、找工作的经验。
进群免费赠送写作秘籍一份,助你由写作小白晋升为创作大佬,进群赠送CSDN评论防封脚本,送真活跃粉丝,助你提升文章热度。
群公告里还有全网大赛约稿汇总/博客提效工具集/CSDN自动化运营脚本 有兴趣的加文末联系方式,备注自己的CSDN昵称,拉你进群,互相学习共同进步。

文章目录

  • [Spring Boot AOP(三) 通知执行链源码解析](#Spring Boot AOP(三) 通知执行链源码解析)
    • [1. 执行链概述](#1. 执行链概述)
    • [2. Advisor 链与通知统一处理](#2. Advisor 链与通知统一处理)
      • [Mermaid 流程图:Advisor 链构建](#Mermaid 流程图:Advisor 链构建)
    • [3. MethodInterceptor 执行流程](#3. MethodInterceptor 执行流程)
      • [3.1 ReflectiveMethodInvocation 核心源码](#3.1 ReflectiveMethodInvocation 核心源码)
      • [3.2 执行逻辑说明](#3.2 执行逻辑说明)
      • [Mermaid 流程图:MethodInterceptor 调用链](#Mermaid 流程图:MethodInterceptor 调用链)
    • [4. 不同通知类型执行链示意](#4. 不同通知类型执行链示意)
    • [5. 环绕通知执行链深入解析](#5. 环绕通知执行链深入解析)
      • [Mermaid 流程图:环绕通知链执行](#Mermaid 流程图:环绕通知链执行)
    • [6. 多 Advisor 链组合示例](#6. 多 Advisor 链组合示例)
    • [7. ReflectiveMethodInvocation 执行链源码示意](#7. ReflectiveMethodInvocation 执行链源码示意)
    • [8. 本文总结](#8. 本文总结)
    • 结束语

Spring Boot AOP(三) 通知执行链源码解析

1. 执行链概述

在 Spring AOP 中,一个方法可能对应 多个切面(Aspect)多个通知(Advice) 。Spring 使用 Advisor 链 + MethodInterceptor 链 来统一管理这些通知,使方法执行时按顺序执行各类通知。

核心概念

概念 说明
Advisor 切面 + 切入点 + 通知的组合对象
Advice 切面中具体执行的操作,例如 @Before、@After、@Around
MethodInterceptor AOP 的统一调用接口,所有 Advice 最终都转换为 MethodInterceptor
ReflectiveMethodInvocation 方法调用封装类,负责顺序调用 Advisor 链

Spring AOP 的通知最终都会被封装为 MethodInterceptor ,执行链由 ReflectiveMethodInvocation 管理。


2. Advisor 链与通知统一处理

在 Spring 中,多个切面可能作用于同一个方法。Spring 会将所有切面对应的通知 排序后加入 Advisor 链

  1. 收集匹配的切面
  2. 将切面中的 Advice 转换为 MethodInterceptor
  3. 按 @Order 或实现 Ordered 接口排序
  4. 构建 ReflectiveMethodInvocation 执行链

Mermaid 流程图:Advisor 链构建

扫描 Bean 切面 匹配切入点 收集匹配的通知 Advice 转换为 MethodInterceptor 按顺序构建 ReflectiveMethodInvocation 链


3. MethodInterceptor 执行流程

3.1 ReflectiveMethodInvocation 核心源码

核心方法:proceed()

java 复制代码
public Object proceed() throws Throwable {
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return this.method.invoke(this.target, this.arguments);
    }

    Object interceptorOrAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrAdvice instanceof MethodInterceptor) {
        return ((MethodInterceptor) interceptorOrAdvice).invoke(this);
    } else {
        return proceed();
    }
}

3.2 执行逻辑说明

  1. currentInterceptorIndex 控制当前执行的通知
  2. 如果到达链尾,则调用目标方法
  3. 否则,将当前通知强转为 MethodInterceptor 并调用
  4. 每个环绕通知内部可以调用 proceed() 执行下一环节

Mermaid 流程图:MethodInterceptor 调用链

flowchart TD A[客户端调用代理方法] --> B[ReflectiveMethodInvocation
proceed] B --> C[@Before 前置通知] C --> D[@Around 环绕通知 - 前半部分] D --> E[proceed 递归调用] E --> F[目标方法执行] F --> G[@Around 环绕通知 - 后半部分] G --> H[@AfterReturning 返回通知

@AfterThrowing 异常通知] H --> I[@After 后置通知] I --> J[返回客户端] style A fill:#BBDEFB style B fill:#FFF9C4 style C fill:#C8E6C9 style D fill:#FFE0B2 style F fill:#FFCDD2 style H fill:#FFCCBC style J fill:#E1BEE7

4. 不同通知类型执行链示意

通知类型 转换为 MethodInterceptor 执行顺序
前置通知 @Before MethodBeforeAdviceInterceptor 最先执行
环绕通知 @Around AroundAdviceInterceptor 可环绕目标方法
返回通知 @AfterReturning AfterReturningAdviceInterceptor 目标方法成功返回后执行
异常通知 @AfterThrowing AfterThrowingAdviceInterceptor 目标方法异常时执行
后置通知 @After AfterAdviceInterceptor 最后执行,无论成功/异常

5. 环绕通知执行链深入解析

环绕通知最灵活,可以完全控制方法执行:

java 复制代码
@Around("execution(* com.example.service..*.*(..))")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
    System.out.println("环绕通知前逻辑");
    Object result = pjp.proceed();
    System.out.println("环绕通知后逻辑");
    return result;
}

Mermaid 流程图:环绕通知链执行

方法调用 环绕通知1前逻辑 环绕通知2前逻辑 目标方法执行 环绕通知2后逻辑 环绕通知1后逻辑 返回调用方


6. 多 Advisor 链组合示例

java 复制代码
@Aspect
@Component
@Order(1)
public class LoggingAspect {
    @Before("execution(* com.example.service..*.*(..))")
    public void before(JoinPoint jp) {
        System.out.println("日志前置: " + jp.getSignature());
    }
}

@Aspect
@Component
@Order(2)
public class TransactionAspect {
    @Around("execution(* com.example.service..*.*(..))")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("事务开始");
        Object result = pjp.proceed();
        System.out.println("事务提交");
        return result;
    }
}

@Aspect
@Component
@Order(3)
public class MetricsAspect {
    @AfterReturning(pointcut = "execution(* com.example.service..*.*(..))", returning = "result")
    public void afterReturning(JoinPoint jp, Object result) {
        System.out.println("性能监控: " + jp.getSignature() + ", 返回: " + result);
    }
}

多切面执行顺序示意

flowchart TD A[方法调用] --> B[LoggingAspect @Before] B --> C[TransactionAspect @Around 前] C --> D[目标方法执行] D --> E[TransactionAspect @Around 后] E --> F[MetricsAspect @AfterReturning] F --> G[返回调用方]

7. ReflectiveMethodInvocation 执行链源码示意

是 否 proceed 方法调用 获取当前索引的 MethodInterceptor 索引是否到达链尾? 执行目标方法 method.invoke 执行当前拦截器 interceptor.invoke this 拦截器内部调用 proceed 返回结果 逐层返回到调用方


8. 本文总结

  • Spring AOP 统一将所有通知封装为 MethodInterceptor
  • ReflectiveMethodInvocation 负责 链式执行所有通知
  • 环绕通知可以完全控制目标方法执行,其他通知按 Advisor 链顺序执行
  • 多切面组合执行顺序由 @OrderOrdered 接口控制
  • Mermaid 图直观展示了 Advisor 链、方法调用链和环绕通知执行顺序

这一篇是 源码级、流程图丰富、示例全面 的第三篇,紧接第二篇的代理机制,完整衔接整个系列。

下一步可以写 第四篇:Spring Boot /error 与 BasicErrorController 源码解析 或你希望继续写 异常与 AOP 结合的执行顺序 这一主题,你希望我直接写哪一个?

结束语

👨‍💻 关于我

持续学习 | 追求真我

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

掘金点击访问Qiuner CSDN点击访问Qiuner GitHub点击访问Qiuner Gitee点击访问Qiuner

专栏 简介
📊 一图读懂系列 图文并茂,轻松理解复杂概念
📝 一文读懂系列 深入浅出,全面解析技术要点
🌟持续更新 保持学习,不断进步
🎯 人生经验 经验分享,共同成长

你好,我是Qiuner. 为帮助别人少走弯路而写博客

如果本篇文章帮到了你 不妨点个 吧~ 我会很高兴的 😄 (^ ~ ^) 。想看更多 那就点个关注吧 我会尽力带来有趣的内容 😎。

代码都在Github或Gitee上,如有需要可以去上面自行下载。记得给我点星星哦😍

如果你遇到了问题,自己没法解决,可以去我掘金评论区问。CSDN评论区和私信消息看不完 掘金消息少一点.

上一篇推荐 链接
Java程序员快又扎实的学习路线 点击该处自动跳转查看哦
一文读懂 AI 点击该处自动跳转查看哦
一文读懂 服务器 点击该处自动跳转查看哦
2024年创作回顾 点击该处自动跳转查看哦
一文读懂 ESLint配置 点击该处自动跳转查看哦
老鸟如何追求快捷操作电脑 点击该处自动跳转查看哦
未来会写什么文章? 预告链接
一文读懂 XX? 点击该处自动跳转查看哦
2025年终总结 点击该处自动跳转查看哦
一图读懂 XX? 点击该处自动跳转查看哦
相关推荐
羑悻的小杀马特3 小时前
【Linux篇章】再续传输层协议TCP:用技术隐喻重构网络世界的底层逻辑,用算法演绎‘网络因果律’的终极推演(通俗理解TCP协议,这一篇就够了)!
linux·网络·后端·tcp/ip·tcp协议
hashiqimiya3 小时前
通过前端修改后端,后端接收数组类型为string
java
BingoGo3 小时前
当遇见 CatchAdmin V5-模块化设计重新定义 Laravel 后台开发
后端·php
Victor3564 小时前
Netty(23)Netty的负载均衡和高可用性如何实现?
后端
Victor3564 小时前
Netty(24)Netty中的零拷贝文件传输
后端
武昌库里写JAVA4 小时前
Java设计模式-(创建型)抽象工厂模式
java·vue.js·spring boot·后端·sql
热河暖男4 小时前
使用 Flying-Saucer-Pdf + velocity 模板引擎生成 PDF(解决中文和图片问题)
java·pdf·html·springboot
程序员爱钓鱼6 小时前
Node.js 编程实战:图像与文件上传下载
前端·后端·node.js
程序员爱钓鱼6 小时前
Node.js 编程实战:日志管理与分析
后端·面试·node.js