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

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

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

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

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


  1. MyBatis插件架构深度解析:多插件责任链模式的实现原理与执行顺序奥秘

  2. 手写MyBatis(七):InterceptorChain设计与多插件嵌套代理的实现策略

  3. 从单插件到多插件:MyBatis插件系统的架构演进与责任链模式实践

  4. MyBatis插件执行顺序揭秘:为什么后配置的插件先执行?


在前一篇文章中,我们探讨了MyBatis插件的基本原理和单个插件的实现方式。然而,在实际的企业级应用中,我们往往需要同时使用多个插件来实现不同的功能,比如同时使用分页插件、性能监控插件和数据加密插件。今天,我们将深入探讨MyBatis如何通过精巧的责任链模式设计,实现对多个插件的协同管理,并解析其执行顺序的内在逻辑。

一、多插件管理的挑战:为何需要InterceptorChain?

单个插件的实现相对简单,但当多个插件同时存在时,就会面临一系列复杂的问题:

  1. 执行顺序问题:多个插件应该按照什么顺序执行?哪个插件的逻辑先处理,哪个后处理?

  2. 代理嵌套问题:如何确保每个插件都能正确拦截目标方法,而不会相互干扰?

  3. 统一管理问题:如何集中管理所有插件,避免散落在代码的各个角落?

MyBatis的解决方案是引入一个专门的管理器——InterceptorChain(拦截器链)。这个类的设计体现了经典的责任链模式(Chain of Responsibility Pattern),它将所有插件组织成一条链,让每个插件都有机会处理请求。

二、InterceptorChain的核心设计与实现

InterceptorChain的核心职责非常明确:管理和执行所有插件。它的实现通常包含以下关键部分:

 public class InterceptorChain {// 存储所有拦截器的列表private final List<Interceptor> interceptors = new ArrayList<>();// 添加插件到链中public void addInterceptor(Interceptor interceptor) {interceptors.add(interceptor);}// 对目标对象应用所有插件public Object pluginAll(Object target) {// 遍历所有插件for (Interceptor interceptor : interceptors) {// 检查插件是否声明要拦截此类对象if (interceptor instanceof Interceptor) {// 使用插件包装目标对象target = interceptor.plugin(target);}}return target;}// 获取所有插件public List<Interceptor> getInterceptors() {return Collections.unmodifiableList(interceptors);}}

这个看似简单的类,却是整个多插件系统的核心。它的pluginAll方法实现了插件的嵌套代理机制。

三、多插件的工作流程:层层代理的魔法

多插件的工作流程可以分为配置阶段和运行时阶段:

1. 配置阶段:插件注册与链构建

在MyBatis初始化时,所有通过配置文件或注解声明的插件都会被添加到InterceptorChain中:

 // 在配置类中InterceptorChain chain = new InterceptorChain();chain.addInterceptor(new PaginationInterceptor());  // 分页插件chain.addInterceptor(new PerformanceInterceptor()); // 性能监控插件chain.addInterceptor(new EncryptionInterceptor());  // 数据加密插件

2. 运行时阶段:四大组件的代理包装

当需要创建ExecutorStatementHandlerParameterHandlerResultSetHandler时,框架会调用InterceptorChain.pluginAll()方法:

 public Executor newExecutor(Transaction transaction, ExecutorType executorType) {// 1. 创建原始的目标对象Executor executor = new SimpleExecutor(transaction);// 2. 应用所有插件executor = (Executor) interceptorChain.pluginAll(executor);return executor;}
四、插件执行顺序的奥秘:后配置先执行

这是一个非常关键且容易混淆的概念:InterceptorChain中,后添加的插件会先执行。这是因为插件是通过嵌套代理的方式实现的,后添加的插件位于代理链的外层。

让我们通过一个具体的例子来理解这个过程:

 // 假设我们按顺序添加三个插件chain.addInterceptor(plugin1); // 最先添加chain.addInterceptor(plugin2); // 其次添加  chain.addInterceptor(plugin3); // 最后添加​// 当调用pluginAll时,实际的包装过程是:Object target = new SimpleExecutor(); // 原始对象target = plugin3.plugin(target);     // 最外层代理target = plugin2.plugin(target);     // 中间层代理target = plugin1.plugin(target);     // 最内层代理

最终的代理结构如下图所示:

从图中可以清晰看出,虽然plugin1最先被添加到链中,但它实际上是最内层的代理,因此最后执行。而plugin3最后被添加,却成为最外层的代理,最先执行。

这种"后进先出"的执行顺序有着重要的实际意义:后添加的插件可以对先添加的插件的处理结果进行再处理。例如,如果先添加数据加密插件,后添加SQL日志插件,那么日志插件记录的是加密后的SQL,这可能不是我们想要的。通过调整添加顺序,我们可以让日志插件先记录原始SQL,然后再由加密插件进行处理。

五、Plugin.wrap方法:代理机制的实现核心

在每个插件的plugin方法中,通常会调用一个统一的工具方法Plugin.wrap()

 public class MyPlugin implements Interceptor {@Overridepublic Object plugin(Object target) {// 使用Plugin工具类创建代理return Plugin.wrap(target, this);}@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 插件的具体逻辑return invocation.proceed();}}

Plugin.wrap()方法的内部实现是理解整个插件机制的关键:

 public class Plugin implements InvocationHandler {public static Object wrap(Object target, Interceptor interceptor) {// 1. 获取插件声明的要拦截的接口和方法Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);// 2. 检查目标对象是否实现了插件要拦截的接口Class<?> type = target.getClass();Class<?>[] interfaces = getAllInterfaces(type, signatureMap);if (interfaces.length > 0) {// 3. 创建动态代理对象return Proxy.newProxyInstance(type.getClassLoader(),interfaces,new Plugin(target, interceptor, signatureMap));}return target;}}

这个方法的核心作用是:只为那些实现了插件声明要拦截的接口的目标对象创建代理。这样就避免了不必要的代理开销,也确保了插件只会拦截它真正关心的方法。

六、总结:责任链模式的价值

MyBatis的多插件机制是一个经典的责任链模式应用,它的价值在于:

  1. 解耦:每个插件只关注自己的功能,不需要知道其他插件的存在。

  2. 灵活扩展:可以轻松地添加、移除或调整插件,而不需要修改框架核心代码。

  3. 执行顺序可控:通过调整插件的添加顺序,可以控制插件的执行顺序。

  4. 职责单一:每个插件都有明确的职责范围,符合单一职责原则。

通过这种精巧的设计,MyBatis提供了一个极其强大且灵活的扩展机制,使得开发者可以在不修改框架源码的情况下,深度定制和增强框架的功能。这种设计思路值得我们深入学习和借鉴,无论是在框架设计还是日常业务开发中,责任链模式都是一种非常有价值的架构模式。


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

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

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

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

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

相关文章

宜春城区光纤铺设及接口实地调研

一、研究方向与近期关注 因为课题研究的原因&#xff0c;最近对城市骨干网非常感兴趣。前期我讨论了5G&#xff0c;WiFi及自组网等无线通信网络情况&#xff0c;感兴趣的朋友可以移步我的博客阅读&#xff1a; 5G无线通信网络场景&#xff08;日常、工业&#xff09;及拓扑结…

Tomcat 企业级运维实战系列(六):综合项目实战:Java 前后端分离架构部署

Tomcat 企业级运维实战系列&#xff08;六&#xff09;&#xff1a;综合项目实战&#xff1a;Java 前后端分离架构部署一&#xff1a;概述二&#xff1a;部署1&#xff09;环境准备2&#xff09;部署数据库3&#xff09;部署后端4&#xff09;部署前端总结&#x1f680; Tomcat…

《Unity Shader入门精要》学习笔记四(高级纹理)

1、立方体纹理解释&#xff1a;站在一个完全透明的玻璃盒子中心&#xff0c;就可以看到6个面。把这个玻璃盒子的6个面都贴上一张照片。这6张照片合起来&#xff0c;就记录了周围360度的环境&#xff0c;比如蓝天、地面、建筑、树木等。在2D纹理中&#xff0c;使用坐标来找颜色&…

局域网中使用Nginx部署https前端和后端

目录 一.前端部署https 二.后端部署https 一.前端部署https 1.前端正常创建项目即可,打包后,文件夹的格式是dist 2.下载认证的证书 也可以使用其他软件,这里推荐使用mkcert,下载地址如下: Releases FiloSottile/mkcert GitHub 3.输入 mkcert -install

K8s卷机制:数据持久化与共享

在 Kubernetes&#xff08;K8s&#xff09;中&#xff0c;卷&#xff08;Volume&#xff09; 是用于解决容器内数据持久化、容器间数据共享以及与外部存储交互的核心机制。它本质上是一个可供 Pod 中容器访问的存储目录&#xff0c;生命周期独立于容器&#xff08;容器重启或销…

线性回归原理推导与应用(十一):多重共线性

多重共线性的定义与影响 多重共线性&#xff08;Multicollinearity&#xff09;是指线性回归模型中的解释变量之间由于存在精确相关关系或高度相关关系而使模型估计失真或难以估计准确。 根据定义和影响程度&#xff0c;可以将多重共线性分为极端共线性和一般共线性。极端共线…

day082-初识ElasticStack

文章目录0. 老男孩思想-人性十大需求1. ElasticStack介绍1.1 ELK&#xff08;**Elastic Stack**&#xff09;1.2 logstash和filebeat的区别2. ElasticSearch单点部署2.1 下载ElasticSearch软件包2.2 安装软件并修改配置文件2.3 启动并测试服务3. ElasticSearch集群部署3.1 安装…

软考 系统架构设计师系列知识点之杂项集萃(139)

接前一篇文章:软考 系统架构设计师系列知识点之杂项集萃(138) 第257题 系统工程利用计算机作为工具,对系统的结构、元素、()和反馈等进行分析,以达到最优()、最优设计、最优管理和最优控制的目的。霍尔(A.D.Hall)于1969年提出了系统方法的三维结构体系,通常称为霍…

solidity地址、智能合约、交易概念

目录地址address 的两种子类型&#xff08;Solidity 0.5.0&#xff09;address分类address 的常用操作和属性总结交易交易的基本结构&#xff08;由外部发起&#xff09;Gas交易生命周期函数调用与交易常见交易场景总结地址 在 Solidity 中&#xff0c;地址&#xff08;addres…

jwt原理及Java中实现

一、JWT 是什么&#xff1f;解决什么问题&#xff1f; 我们先来一张图看一下这个过程&#xff1a;JWT&#xff08;JSON Web Token&#xff09;是一种把“认证信息&#xff08;Claims&#xff09; 完整性校验”打包成 自包含 的字符串的规范。 它主要用于无状态认证&#xff1a;…

大数据在UI前端的应用深化研究:用户行为数据的跨平台关联分析

大数据在UI前端的应用深化研究&#xff1a;用户行为数据的跨平台关联分析每天&#xff0c;你在手机 App 里点了一个按钮、在网页上滑了两屏、又在小程序里停留了 3 秒&#xff0c;这些看似零散的动作&#xff0c;其实都在被悄悄记录。过去&#xff0c;这些数据只能各自躺在自己…

C++11基础——— 右值引用和移动语义

1. C11的发展历史 C11是C的第⼆个主要版本&#xff0c;并且是从C98起的最重要更新。它引入了大量更改&#xff0c;标准化了既有实践&#xff0c;并改进了对C程序员可用的抽象。在它最终由ISO在2011年8月12日采纳前&#xff0c;人们曾使用名称“C0x”&#xff0c;因为它曾被期待…

【一】Django框架版本介绍

【一】Django框架版本介绍 【一】Django框架版本 ● Django 是一个高级的Python Web框架&#xff0c;由荷兰人Armin Ronacher创建。 ● 随着版本的迭代和功能的不断优化&#xff0c;Django在处理异步请求方面也有了显著的进步。 【1】Django1.x ● 默认不支持异步 ● Django 1.…

git 大文件上传不了的 问题

你 还是在 cmd 里执行&#xff0c;Select-String 是 PowerShell 的命令&#xff0c;cmd 不认识。 请务必按下面的步骤 切换到 PowerShell 再运行。✅ 1. 打开 PowerShell&#xff08;不要再用 cmd&#xff09;最简单&#xff1a; 在资源管理器里进入 D:\linShiWenjian\my-react…

【FIX】go运行报错“missing go.sum entry for module providing package”解决方案

&#x1f527; ​核心解决方案​**运行 go mod tidy**​ ​作用​&#xff1a;自动同步 go.mod和 go.sum文件&#xff0c;添加缺失依赖并移除无用条目。 go mod tidy​适用场景​&#xff1a;90% 的校验和缺失问题可通过此命令解决。 ​注意​&#xff1a;若项目含私有仓库&…

【实操教学】ArcGIS 如何进行定义坐标系

一、坐标系定义的方式创建数据时可直接完成坐标系定义&#xff1b;针对已创建的数据集&#xff08;涵盖要素类、要素数据集及栅格数据集&#xff09;&#xff0c;则可通过以下这种方式定义&#xff1a;工具箱工具调用&#xff1a;使用 ArcGIS 工具箱中的 “定义投影&#xff08…

如何使用Windows自带的PnPUtil命令来禁用/停用和启用硬件设备

我来详细讲解一下如何使用 Windows 自带的 PnPUtil 命令来禁用&#xff08;停用&#xff09; 和启用硬件设备。 PnPUtil (即插即用实用工具) 是一个功能强大的命令行工具&#xff0c;主要用于安装、卸载、枚举和修改驱动程序包。对于硬件的启用和禁用&#xff0c;它通过操作设…

鸿蒙Next媒体展示组件实战:Video与动态布局全解析

今天我们来深入探讨HarmonyOS Next中几种核心媒体展示组件的使用方法&#xff0c;通过实际代码示例展示如何打造丰富的多媒体体验。HarmonyOS Next为开发者提供了一套强大而灵活的媒体展示组件&#xff0c;使开发者能够轻松实现视频播放、动态布局适应、全屏切换等常见多媒体功…

复现RoboDK机器人校准功能(以Staubli TX2‑90L / TX200机械臂为测试对象,实测精度接近原厂)

本算法复现了 RoboDK 的机器人校准功能&#xff1a;在训练集的理论校准后精度与 RoboDK 一致&#xff0c;在测试集的实测精度接近 Staubli 原厂。 参考&#xff1a;RoboDK 机器人校准功能&#xff08;https://robodk.com.cn/cn/robot-calibration&#xff09; 特性 支持 SDH 参…

Vue常用指令和生命周期

Vue 是基于 MVVM模型的前端 JavaScript 框架。Vue 核心是数据驱动视图&#xff0c;通过响应式数据实现视图自动更新。<template><div>{{ message }}</div><button click"changeMsg">修改内容</button> </template><script se…