手写MyBatis第47弹:Interceptor接口设计与Invocation上下文传递机制--MyBatis动态代理生成与方法拦截的精妙实现

🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐是作者创作的最大动力🤞

💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝欢迎留言讨论

🔥🔥🔥(源码 + 调试运行 + 问题答疑)

🔥🔥🔥  有兴趣可以联系我。

我们常常在当下感到时间慢,觉得未来遥远,但一旦回头看,时间已经悄然流逝。对于未来,尽管如此,也应该保持一种从容的态度,相信未来仍有许多可能性等待着我们。 

目录

一、Interceptor接口:插件系统的契约

二、Invocation对象:调用上下文的完整封装

三、proceed()方法:链式调用的引擎

四、Plugin.wrap方法:代理生成的工厂

五、插件如何修改参数和返回值

六、总结:链式调用的设计哲学


  1. MyBatis插件链式调用深度解析:Interceptor接口设计与Invocation上下文传递机制

  2. 手写MyBatis(八):插件链式调用与Invocation.proceed的递归魔法

  3. 从拦截到修改:MyBatis插件如何操纵方法参数与返回值的核心技术

  4. Plugin.wrap方法揭秘:MyBatis动态代理生成与方法拦截的精妙实现


在上一篇文章中,我们探讨了MyBatis多插件管理的责任链模式。今天,我们将深入这个链条的内部,解析链式调用的实现细节,特别是Interceptor接口的设计、Invocation对象的作用以及proceed()方法如何实现递归调用。这些看似简单的组件背后,隐藏着MyBatis插件系统最精妙的设计思想。

一、Interceptor接口:插件系统的契约

Interceptor接口是MyBatis插件系统的核心契约,它定义了插件必须实现的三个关键行为:

 public interface Interceptor {// 核心拦截方法:包含插件的主要逻辑Object intercept(Invocation invocation) throws Throwable;// 默认方法:用于包装目标对象生成代理default Object plugin(Object target) {return Plugin.wrap(target, this);}// 设置插件属性(可选)default void setProperties(Properties properties) {// 默认空实现}}

这个接口设计的精妙之处在于:

  1. intercept方法:这是插件的核心,包含了插件的主要业务逻辑。它接收一个Invocation参数,这个参数封装了完整的调用上下文。

  2. plugin默认方法:这是一个非常巧妙的设计。通过提供默认实现,MyBatis让插件开发者无需关心复杂的代理生成逻辑,只需要专注于业务逻辑的实现。这个方法确保了所有插件都使用统一的代理生成机制。

  3. setProperties方法:允许插件接收外部配置参数,增强了插件的灵活性。

二、Invocation对象:调用上下文的完整封装

Invocation对象是插件链式调用的核心载体,它封装了一次方法调用的所有必要信息:

 public class Invocation {private final Object target;     // 被代理的原始对象private final Method method;     // 被拦截的方法private final Object[] args;     // 方法参数public Invocation(Object target, Method method, Object[] args) {this.target = target;this.method = method;this.args = args;}// 关键方法:继续执行调用链public Object proceed() throws InvocationTargetException, IllegalAccessException {return method.invoke(target, args);}// Getter方法public Object getTarget() { return target; }public Method getMethod() { return method; }public Object[] getArgs() { return args; }// 设置参数(用于修改参数)public void setArgs(Object[] args) { this.args = args; }}

Invocation的设计体现了"信息专家"模式——它将一次方法调用的所有相关信息集中管理,为插件提供了完整的操作上下文。

三、proceed()方法:链式调用的引擎

proceed()方法是整个插件链式调用机制的核心。它的作用看似简单——调用目标方法,但在责任链模式中,它的行为实际上要复杂得多:

从图中可以看出,proceed()方法实际上触发了一个递归的调用过程:

  1. 最外层插件首先执行前置处理逻辑

  2. 调用proceed(),该方法实际上会调用下一个插件intercept方法

  3. 这个过程递归进行,直到最后一个插件调用proceed()

  4. 最后一个proceed()调用原始目标方法

  5. 然后调用栈逐层返回,每个插件执行后置处理逻辑

  6. 最终返回到最外层插件,完成整个调用链

这种设计的美妙之处在于:每个插件都无需知道整个调用链的结构,它只需要调用proceed()并将处理权交给链条的下一个环节即可

四、Plugin.wrap方法:代理生成的工厂

Plugin.wrap()是插件机制中的另一个关键组件,它负责创建动态代理对象:

 public class Plugin implements InvocationHandler {private final Object target;                 // 原始对象private final Interceptor interceptor;       // 插件实例private final Map<Class<?>, Set<Method>> signatureMap; // 方法签名映射public static Object wrap(Object target, Interceptor interceptor) {// 获取插件声明的拦截点Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);Class<?> type = target.getClass();// 获取目标对象实现的所有需要被拦截的接口Class<?>[] interfaces = getAllInterfaces(type, signatureMap);if (interfaces.length > 0) {// 创建动态代理return Proxy.newProxyInstance(type.getClassLoader(),interfaces,new Plugin(target, interceptor, signatureMap));}return target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 检查当前方法是否需要被拦截Set<Method> methods = signatureMap.get(method.getDeclaringClass());if (methods != null && methods.contains(method)) {// 如果需要拦截,调用插件的intercept方法return interceptor.intercept(new Invocation(target, method, args));}// 否则直接调用原始方法return method.invoke(target, args);}}

Plugin.wrap()的智能之处在于它只会为那些实现了插件声明要拦截的接口的对象创建代理,避免了不必要的性能开销。

五、插件如何修改参数和返回值

基于上述架构,插件可以很容易地修改方法参数和返回值:

1. 修改方法参数:

 @Overridepublic Object intercept(Invocation invocation) throws Throwable {// 获取原始参数Object[] args = invocation.getArgs();// 修改参数(例如加密参数)if (args[0] instanceof String) {args[0] = encrypt((String) args[0]);}// 重要:将修改后的参数设置回Invocationinvocation.setArgs(args);// 继续执行调用链return invocation.proceed();}

2. 修改返回值:

 @Overridepublic Object intercept(Invocation invocation) throws Throwable {// 执行原有逻辑并获取返回值Object result = invocation.proceed();// 修改返回值(例如解密结果)if (result instanceof String) {result = decrypt((String) result);}return result;}

3. 完全替换方法逻辑:

 @Overridepublic Object intercept(Invocation invocation) throws Throwable {// 不调用proceed,完全由插件实现方法逻辑if (shouldReplaceLogic(invocation)) {return customLogic(invocation);}// 否则正常执行原有逻辑return invocation.proceed();}
六、总结:链式调用的设计哲学

MyBatis插件链式调用机制的设计体现了多个重要的软件设计原则:

  1. 开闭原则:通过插件机制,可以在不修改框架源码的情况下扩展功能。

  2. 单一职责原则:每个插件只关注一个特定的功能点。

  3. 依赖倒置原则:插件依赖于抽象的Interceptor接口,而不是具体的实现。

  4. 信息专家模式Invocation对象集中管理了调用相关的所有信息。

这种设计不仅使得MyBatis插件系统极其强大和灵活,也为我们提供了如何设计可扩展架构的宝贵范例。无论是开发框架还是业务系统,这种责任链模式和链式调用的思想都值得深入学习和应用。


💖学习知识需费心,
📕整理归纳更费神。
🎉源码免费人人喜,
🔥码农福利等你领!

💖常来我家多看看,
📕我是程序员扣棣,
🎉感谢支持常陪伴,
🔥点赞关注别忘记!

💖山高路远坑又深,
📕大军纵横任驰奔,
🎉谁敢横刀立马行?
🔥唯有点赞+关注成!

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

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

相关文章

自动驾驶中的传感器技术37——Lidar(12)

这里对当前Lidar中的一些常见问题进行专项论述。首先以禾赛Lidar为例&#xff0c;列出相关参数&#xff0c;以备论述。 图1 禾赛AT128参数图2 禾赛AT360参数图3 禾赛AT1440参数图4 禾赛AT128可靠性验证项图5 禾赛AT128产品证书1、Lidar的线束是什么&#xff0c;由什么决定&…

Meteor主题友链页面自研

发布于&#xff1a;Eucalyptus-Blog Meteor主题虽然设计简约现代&#xff0c;但由于缺乏原生的友情链接管理功能&#xff0c;许多博主只能将友情链接勉强添加在网站底部&#xff0c;这不仅影响页面美观&#xff0c;也不便于访客查找和互动&#xff1b;为了解决这一痛点&#xf…

QT控件QPlainTextEdit、QTextEdit与QTextBrowser的区别

一.主要功能对比二.关键功能差异1.文本类型支持QPlainTextEdit&#xff1a;仅支持纯文本&#xff08;Plain Text&#xff09;&#xff0c;不处理任何格式&#xff08;如字体、颜色、链接、图片等&#xff09;。文本以原始字符形式存储&#xff0c;适合处理日志、代码、配置文件…

【思考】WSL是什么

WSL WSL是什么呢&#xff1f; WSL 是 windows subsystem for linux 的简写&#xff0c;指的是 windows10 的一个子系统&#xff0c;这个子系统的作用是在 windows 下运行 linux 操作系统。 有了WSL&#xff0c;就可以在 windows10 中运行linux操作系统了。许多在 linux 种运行的…

基于单片机智能饮水机/智能热水壶

传送门 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品题目速选一览表 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品题目功能速览 概述 基于单片机的智能饮水机系统通过嵌入式技术实现水温控制、水量监测及用户交互功能。系统采用STM3…

Unity游戏打包——iOS打包基础、传包

本文由 NRatel 历史笔记整理而来&#xff0c;如有错误欢迎指正。 相关参考文档 Unity文档 -> 平台开发 -> IOS https://docs.unity3d.com/cn/2021.3/Manual/iphone.html Unity导出的Xcode 项目的结构 Modifying an Xcode project use Xcode.PBXProject. https://doc…

pyside6小项目:进制转换器

from PySide6.QtUiTools import QUiLoader from PySide6.QtWidgets import QApplication,QWidgetclass MyWindow(QWidget):def __init__(self):super().__init__()self.ui QUiLoader().load(trans.ui)self.ui.show()#stor data type dictionaryself.lengthVar {米:100, 千米:…

再见 K8s!3款开源的云原生部署工具

前文&#xff0c;和大家分享了云原生中的核心工具 K8s&#xff1a; 关于 K8s&#xff1a;入门&#xff0c;这篇就够了 K8s是个好东西&#xff0c;就是上手门槛有点高。这不&#xff0c;需求就来了&#xff1f; 有需求&#xff0c;就有工具。 为了解决K8s的配置难题&#xf…

C++ 快速复习指南(上半部分)

1.基础语法基本结构#include <iostream> 头名 using namesapce std ; 统一使用命名空间 int main () { 程序执行门户 主题内容}基本输出 cout << "string " << endl; // 输出 string 变量和数据类型 格式int intger 10 ;常量的引入 需要在变量…

ArcGIS Pro 地图打包与解包

如果需要在ArcGIS Pro 打包某一个地图文档&#xff0c;在 菜单栏中 点击 共享&#xff0c;点击地图。弹出 打包地图 面板&#xff0c;可以打包到Online、打包到地图包&#xff0c;选择将包保存到文件&#xff0c;修改项目详细信息&#xff0c;点击 包&#xff0c;即可实现打包。…

sunset: twilight靶场

sunset: twilight 来自 <sunset: twilight ~ VulnHub> 1&#xff0c;将两台虚拟机网络连接都改为NAT模式 2&#xff0c;攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.128&#xff0c;靶场IP192.168.23.145 3&#xff0c;对靶机…

【机器学习基础】无监督学习算法的现代演进:从数据探索到智能系统的自主发现能力

1. 引言:无监督学习在人工智能革命中的核心价值 在人工智能技术飞速发展的今天,无监督学习正在成为推动AI系统实现真正智能的关键技术。与需要大量标注数据的监督学习不同,无监督学习能够从原始数据中自主发现隐藏的模式和结构,这种能力使其在现代AI应用中具有不可替代的价…

PetaLinux的JTAG启动

csdn–PetaLinux 使用技巧与缓存配置 xilinx官网–PetaLinux 工具文档参考指南 (ug1144) xilinx官网–设备树配置文档 内核官网–设备树文档 软硬件准备 分类项目说明/用途验证方法示例硬件JTAG 线JTAG 下载、调试—UART 串口线查看 zynq 启动日志—网口线用于 TFTP 下载—…

单片机中的按键防抖

按钮&#xff08;按键&#xff09;抖动是单片机开发中常见的硬件问题&#xff0c;本质是机械触点接触瞬间的物理弹跳导致的电信号不稳定。消除抖动&#xff08;防抖&#xff09;是确保按键状态检测准确的关键&#xff0c;下面从原理到实现详细讲解。 一、按钮抖动的原理&#x…

面经分享--小米Java一面

目录 1.Kafka和RocketMQ的区别 2.反射的作用 3.类加载的具体过程&#xff0c;双亲委派模型的机制 4.TCP的四次挥手 5.多线程的优势 6.死锁产生的原因&#xff0c;怎么解决 7.Java并发的工作原理 8.常用的git命令 9.算法题 1.leetcode 3.无重复字符的最长子串&#xff…

Python在边缘计算与物联网中的创新实践:实时数据处理与设备控制

近年来&#xff0c;Python语言的普及度持续攀升&#xff0c;尤其在人工智能、数据科学等热门领域备受青睐。然而&#xff0c;一个新兴趋势——边缘计算与物联网&#xff08;IoT&#xff09;的结合——正悄然改变技术格局。边缘计算强调在数据源头进行实时处理&#xff0c;减少云…

Spring Cloud Gateway 网关(五)

目录 一 概念引入 二 具体使用 1 首先创建一个网关模块 2 启动类 3 配置类 4 对应方法的修改 5 展示借助81端口进行转发控制 6 断言规则​编辑 三 过滤器 1 将前置的请求参数给过滤掉&#xff0c;降低繁琐程度。 2 默认过滤器 3 全局过滤器 4 自定义过滤器工厂 5…

产品经理操作手册(8)——业务需求文档(BRD)

一、BRD的定义与价值 **业务需求文档(BRD)**是产品开发前期的基础性文档&#xff0c;它将业务诉求转化为结构化的产品需求&#xff0c;是连接业务方与交付团队的桥梁。“BRD不仅是一份文档&#xff0c;而是一个对齐的过程。”BRD核心价值 统一认知&#xff1a;确保各方对业务目…

Excel表格多级下拉选项,如何制作?

之前分享过如何设置下拉选项&#xff0c;但那只是简单的一级下拉菜单&#xff0c;今天再给大家分享多级下拉菜单如何制作。也就是根据前面的下拉选项改变后面的选项。 我们现来复习一级下拉菜单&#xff0c;再接着讲多级下拉菜单 一级下拉选项 首先我们先将表格内容凑填写好…

[Sync_ai_vid] 唇形同步评判器 | 图像与视频处理器 | GPU测试

第4章&#xff1a;SyncNet唇形同步评判器 在前几章中&#xff0c;我们了解了唇形同步推理流程如何协调生成唇形同步视频&#xff0c;以及音频特征提取器(Whisper)如何为LatentSync UNet提供关键音频线索。 UNet利用这些线索巧妙调整唇部动作。但我们如何判断UNet的生成效果&a…