⚙️ 一、通知到 MethodInterceptor 的转换机制

Spring AOP 通过适配器模式将开发者定义的注解型通知(如 @Before)统一转换为 MethodInterceptor 接口实现,确保所有通知类型能接入同一调用链。以下是转换细节:

1. 适配器实现原理

  • 核心接口:MethodInterceptor是所有通知的最终形态,其invoke(MethodInvocation mi)方法封装了通知逻辑与链式调用逻辑。
  • 适配器作用:将不同通知类型(如AspectJMethodBeforeAdvice)包装为MethodInterceptor子类,实现逻辑转换。

2. 各通知类型的转换细节

下表总结了五种通知的转换逻辑与执行顺序:

通知类型原始接口转换后实现invoke() 核心逻辑
@BeforeAspectJMethodBeforeAdviceMethodBeforeAdviceInterceptor1. 执行 advice.before()
2. 调用 mi.proceed() 触发后续链
@AfterAspectJAfterAdviceAfterAdviceInterceptor1. try { mi.proceed() }
2. finally { advice.after() }(确保最终执行)
@AfterReturningAspectJAfterReturningAdviceAfterReturningAdviceInterceptor1. 调用 mi.proceed()
2. 若正常返回,执行 advice.afterReturning()
@AfterThrowingAspectJAfterThrowingAdviceThrowsAdviceInterceptor1. try { mi.proceed() }
2. catch(ex) { advice.afterThrowing(ex) }
@AroundAspectJAroundAdvice1. 自定义前后逻辑
2. 通过 mi.proceed() 触发后续链(需主动调用)

关键设计:除 @Around 外,所有通知均被转换为环绕通知形式,通过统一的 invoke() 接口接入调用链。


🔄 二、MethodInvocation 与拦截器链的协同流程

1. 调用链构建过程

  1. 代理对象创建:Spring 容器启动时,扫描所有Advisor(包含通知与切点)。
  2. 适配器转换:通过AdvisorAdapterRegistryAdvisor中的通知转换为MethodInterceptor
  3. 链式存储:生成List<MethodInterceptor>并注入ReflectiveMethodInvocation

2. 调用链执行逻辑(ReflectiveMethodInvocation.proceed()

public class ReflectiveMethodInvocation implements MethodInvocation {private final List<MethodInterceptor> interceptors;private int currentInterceptorIndex = -1;  // 当前执行位置索引public Object proceed() throws Throwable {// 1. 所有拦截器执行完毕 → 反射调用目标方法if (this.currentInterceptorIndex == interceptors.size() - 1) {return invokeJoinpoint(); }// 2. 获取下一个拦截器并推进索引MethodInterceptor interceptor = interceptors.get(++currentInterceptorIndex);// 3. 执行当前拦截器(触发统一的invoke接口)return interceptor.invoke(this);  // 将自身(MethodInvocation)传入}
}

索引机制currentInterceptorIndex 记录当前执行位置,每次 proceed() 调用时递增,实现拦截器的顺序触发。

3. 各通知在调用链中的协作顺序

以下序列图展示了典型调用流程(含多个通知类型):

ReflectiveMethodInvocationBefore拦截器Around拦截器After拦截器目标方法interceptor.invoke(this)1执行@Before逻辑2调用proceed()3interceptor.invoke(this)4环绕前逻辑5调用proceed()6interceptor.invoke(this)7调用proceed()8反射调用目标方法9返回结果10执行@After逻辑11返回12环绕后逻辑13返回14返回最终结果15ReflectiveMethodInvocationBefore拦截器Around拦截器After拦截器目标方法

协作关键

  • 嵌套执行:每个拦截器通过调用mi.proceed()触发后续拦截器或目标方法,形成嵌套调用栈。
  • 逻辑控制权:拦截器可决定是否调用proceed()。例如权限校验失败时,Before拦截器可不调用proceed(),直接中断链。

🧩 三、统一 MethodInterceptor 的设计价值

1. 外部易用性

开发者通过直观注解(如 @Before)声明切面,无需理解底层调用链。适配器模式隐藏了复杂性,例如:

@Before("execution(* com.dwl.*.*(..))")
public void logBefore(JoinPoint jp) {System.out.println("Before: " + jp.getSignature());
}

2. 内部统一性

  • 单一执行逻辑:ReflectiveMethodInvocation.proceed()只需遍历List<MethodInterceptor>,无需区分通知类型。
  • 扩展性:新增通知类型时,只需实现适配器并注册到AdvisorAdapterRegistry,无需修改调用链核心逻辑。

3. 异常处理优势

  • 统一异常传播:异常沿调用链反向传递,由最近的@AfterThrowing@Around拦截器捕获。
  • 资源清理保证:@After逻辑在finally块执行,确保即使目标方法异常也能运行(如关闭数据库连接)。

⚡ 四、完整流程案例:日志切面执行

假设切面包含 @Before@Around@After 通知,调用链构建与执行如下:

  1. 转换阶段

    • @BeforeMethodBeforeAdviceInterceptor
    • @AroundAspectJAroundAdvice
    • @AfterAfterAdviceInterceptor
  2. 调用链执行顺序

    调用proceed
    调用proceed
    调用proceed
    返回
    执行finally逻辑
    执行环绕后逻辑
    Before拦截器
    Around拦截器
    After拦截器
    目标方法
  3. 异常场景:若目标方法抛出异常:

    • After 拦截器在 finally 中执行日志清理。
    • 异常传递给Around拦截器,由其捕获并记录。

💎 总结

  1. 转换必然性:适配器模式是 Spring AOP 的基石,将注解通知统一转为MethodInterceptor,实现调用链标准化。
  2. 协同核心:ReflectiveMethodInvocation通过索引控制与嵌套调用(proceed())协调拦截器执行,形成责任链模式。
  3. 设计价值:
    • 对外:简化开发,通过注解屏蔽底层复杂度。
    • 对内:通过统一接口减少冗余代码,提升扩展性。
    • 健壮性:异常处理与资源清理机制保障业务逻辑安全。

此设计完美体现了 “开闭原则”:新增通知类型无需修改调用链核心,仅需扩展适配器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/92888.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/92888.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/92888.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PPO原论文阅读

一、Introduction1.目前存在的问题&#xff1a;(deep)Q-learning:在一些简单问题上表现不佳&#xff0c;可理解性差基础的policy gradient算法&#xff1a;&#xff08;如REINFORCE&#xff09;鲁棒性差&#xff0c;需要大量数据TRPO&#xff1a;复杂&#xff0c;在包含噪音&am…

零基础也能创作专属歌曲:文心一言+蘑兔AI协同教程

在AI技术飞速发展的今天&#xff0c;音乐创作已不再是专业音乐人的专属领域。通过文心一言与蘑兔AI的协同使用&#xff0c;即使没有音乐基础&#xff0c;也能轻松完成从歌词创作到作曲编曲的全流程。本文将详细拆解操作步骤&#xff0c;助你快速上手&#xff0c;实现音乐创作梦…

图论:搜索问题

提到图论中的搜索问题&#xff0c;首先想到的也就是DFS和BFS了&#xff0c;而提到这两种搜索&#xff0c;那么最典型的题目就是岛屿问题了&#xff0c;下面就练习几道相关的题目&#xff0c;为之后的更深奥的图论学习打下基础&#xff01; 孤岛的总面积 题目链接&#xff1a;…

AI驱动攻防升级,API安全走到关键档口

在数字化转型与AI技术快速发展的双重驱动下&#xff0c;API已成为企业业务与外部世界连接的神经中枢。然而&#xff0c;随着API的深度应用&#xff0c;针对API的攻击规模与复杂性也在持续升级。 API为何频频成为黑客重点盯防的突破口&#xff1f;企业常见的API防护手段是否还能…

网络基础DAY18-动态路由协议基础

动态路由协议基础知识回顾&#xff1a;1.什么是路由&#xff1f; 答&#xff1a;是三层设备转发IP报文的路径信息。 2.路由有哪些来源&#xff1f; 答&#xff1a;1.直连路由2.静态路由3.动态路由 3.有直连路由的条件&#xff1f; 答&#xff1a;1.二层和三层物理接口状态为UP …

axios统一封装规范管理

新建/api/ 1.新建统一处理文件/api/axios.ts import axios from "axios"const http axios.create({baseURL: import.meta.env.VITE_API_BASE_URL, // 从环境变量读取timeout: 10000, });// 请求拦截器&#xff08;如添加 Token&#xff09; http.interceptors.reque…

Java学习第七十四部分——Elasticsearch(ES)

目录 一、前言提要 二、核心特性 三、应用场景 四、主要优势 五、集成方式 六、基础操作 七、高级特性 八、概念类比——与关系型数据库 九、简单示例——实现存储与搜索 十、生态集成——基于Spring Data Elasticsearch 十一、性能优化建议 十二、总结归纳概述 一…

TDengine 转化函数 TO_UNIXTIMESTAMP 用户手册

TDengine TO_UNIXTIMESTAMP 函数用户使用手册 函数概述 TO_UNIXTIMESTAMP 是 TDengine 中的标量函数&#xff0c;用于将符合 ISO8601/RFC3339 标准的日期时间字符串转换为 Unix 时间戳。与 TO_TIMESTAMP 不同&#xff0c;该函数专门处理标准格式的时间字符串&#xff0c;无需指…

Java 中的排序算法详解

目录 一、冒泡排序&#xff08;Bubble Sort&#xff09; 原理​ 二、选择排序&#xff08;Selection Sort&#xff09; 原理​ 三、插入排序&#xff08;Insertion Sort&#xff09; 原理​ 四、快速排序&#xff08;Quick Sort&#xff09; 原理​ 五、归并排序&…

Gitee如何成为国内企业DevOps转型的首选平台?

Gitee如何成为国内企业DevOps转型的首选平台&#xff1f; 在数字化转型浪潮中&#xff0c;DevOps已成为提升企业研发效能的关键引擎。作为国内领先的代码托管与协作平台&#xff0c;Gitee凭借本土化优势与全流程支持能力&#xff0c;正成为越来越多企业DevOps实践的核心载体。本…

​Excel——SUMPRODUCT 函数

SUMPRODUCT 是 Excel 中最强大的函数之一&#xff0c;可以用于 ​多条件求和、加权计算、数组运算​ 等复杂场景。下面通过 ​基础语法 实用案例​ 彻底讲透它的用法&#xff01;​一、基础语法​SUMPRODUCT(数组1, [数组2], [数组3], ...)​功能​&#xff1a;将多个数组的对…

告别虚函数性能焦虑:深入剖析C++多态的现代设计模式

🚀 引言:当多态遇上性能瓶颈 我经常被问到这样一个问题:“既然virtual函数这么方便,为什么在一些高性能场景下,大家却避之不及?” 答案很简单:性能。 在我参与的多个HPC项目和游戏引擎开发中,virtual函数调用往往成为性能分析工具中最显眼的那个红点。一个看似无害…

k8s-MongoDB 副本集部署

前提准备一套 k8s 集群worker 节点上的 /nfs/data 目录挂载到磁盘一、NFS 高可用方案&#xff08;NFSkeepalivedSersync&#xff09;本方案 NFS 的高可用方案&#xff0c;应用服务器为 Client &#xff0c;两台文件服务器分别 Master 和 Slave&#xff0c;使用 keepalived 生成…

BI 系统数据看板全解析:让数据可视化驱动业务决策

BI 系统数据看板全解析&#xff1a;让数据可视化驱动业务决策在 BI 系统中&#xff0c;数据看板是连接原始数据与业务洞察的 “桥梁”。它将零散的业务指标转化为直观的可视化图表&#xff0c;让产品经理、运营人员等角色能快速把握业务动态。一个设计精良的数据看板&#xff0…

图机器学习(14)——社交网络分析

图机器学习&#xff08;14&#xff09;——社交网络分析0. 前言1. 数据集分析1.1 数据集介绍1.2 使用 networkx 加载数据集2. 网络拓扑和社区检测2.1 网络拓扑2.2 社区检测0. 前言 社交网站的崛起是近年来数字媒体领域最活跃的发展趋势之一&#xff0c;数字社交互动已经融入人…

深入解析Hadoop MapReduce中Reduce阶段排序的必要性

MapReduce概述与Reduce阶段简介MapReduce作为Hadoop生态系统的核心计算框架&#xff0c;其设计思想源自Google论文&#xff0c;通过"分而治之"的理念实现海量数据的并行处理。该模型将计算过程抽象为两个关键阶段&#xff1a;Map阶段负责数据分解和初步处理&#xff…

7月23日华为机考真题第二题-200分

📌 点击直达笔试专栏 👉《大厂笔试突围》 💻 春秋招笔试突围在线OJ 👉 笔试突围OJ bishipass.com 02. 图书馆资源分配系统 问题描述 A先生是一位图书馆管理员,负责管理图书采购和分配工作。图书馆收到了来自不同出版社的图书批次,同时有多位读者代表排队申请图书…

基于深度学习的图像分类:使用ResNet实现高效分类

最近研学过程中发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击链接跳转到网站人工智能及编程语言学习教程。读者们可以通过里面的文章详细了解一下人工智能及其编程等教程和学习方法。下面开始对正文内容的…

JVM:工具

JVMjpsjstatjmapjhatjstackjconsolejvisualvmjps jps&#xff08; Java Virtual Machine Process Status Tool &#xff09;&#xff0c;是 JDK 中的一个命令行工具&#xff0c;用于列出当前正在运行的 JVM 实例的信息。其对于监控和管理运行在多个 JVM 上的 Java 应用程序特别…

Elasticsearch Circuit Breaker 全面解析与最佳实践

一、Circuit Breaker 简介 Elasticsearch 是基于 JVM 的搜索引擎&#xff0c;其内存管理十分重要。为了避免单个操作或查询耗费过多内存导致节点不可用&#xff0c;Elasticsearch 引入了 Circuit Breaker&#xff08;熔断器&#xff09;机制。当内存使用达到熔断器预设阈值时&a…