当前位置: 首页 > ops >正文

手写MyBatis第43弹:插件拦截原理与四大可拦截对象详解

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

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

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

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

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

  1. 手写MyBatis阶段总结:从CRUD到架构优化,迈向插件开发新征程

  2. MyBatis框架设计深度解析:插件拦截原理与四大可拦截对象详解

  3. 从执行器优化到插件机制:手写MyBatis的架构演进与设计思想

  4. MyBatis插件开发完全指南:揭秘Interceptor链的实现原理与应用场景


在我们手写MyBatis的系列旅程中,我们已经成功搭建了一个具备完整CRUD功能的ORM框架雏形。从最初的配置解析、Mapper代理机制,到SQL执行器、参数处理、结果集映射,再到最近的返回值类型适配和Executor职责分离,我们的框架已经完成了从"能用"到"好用"的关键进化。此刻,让我们暂作停留,回顾已实现的核心功能,并前瞻性地探索MyBatis最强大的特性之一——插件机制。

一、阶段成果回顾:我们构建了什么?

我们的迷你MyBatis框架已经具备了现代ORM框架的核心骨架:

  1. 完整的CRUD操作:支持通过Mapper接口和SqlSession两种方式执行增删改查,其中增删改操作还能智能适配void、int、boolean等多种返回值类型。

  2. 清晰的核心组件协作:各个组件职责分明,形成了精密的协作体系:

  3. 优化的架构设计:通过最近的重构,我们实现了关键职责的分离:

    • 连接管理职责移交给了Transaction接口

    • Statement创建和执行职责移交给了StatementHandler hierarchy

    • Executor现在更加专注于执行流程的调度和控制

二、迈向高级特性:为什么需要插件机制?

尽管我们的框架已经功能完备,但在实际企业级应用中,我们经常需要一些横切关注点(Cross-Cutting Concerns)的功能:

  • SQL性能监控:记录每条SQL的执行时间

  • 分页处理:自动为查询语句添加分页参数

  • 数据权限过滤:根据用户权限自动添加数据过滤条件

  • SQL改写:优化或调整生成的SQL语句

  • 敏感数据加密/解密:在参数设置和结果获取时进行数据转换

如果将这些功能硬编码到框架核心中,会导致代码臃肿且难以维护。插件机制正是为了解决这个问题而生的——它允许在不修改框架源码的情况下,通过外部插件来扩展和增强框架功能。

三、插件机制深度解析:四大可拦截对象

MyBatis的插件可以拦截四大核心组件的方法执行,这也是插件机制的强大之处:

  1. Executor:这是最常被拦截的对象,可以拦截的方法包括:

    • update():增删改操作的入口

    • query():查询操作的入口

    • commit()rollback():事务相关操作

    • flushStatements():批处理操作 应用场景:实现二级缓存、SQL执行时间监控、批量操作优化等。

  2. StatementHandler:SQL语句执行的核心处理器,可拦截:

    • prepare():创建Statement时

    • parameterize():设置参数时

    • query()update():执行SQL时 应用场景:分页插件(改写SQL)、性能监控、参数加密等。

  3. ParameterHandler:参数处理器,可拦截:

    • setParameters():设置参数到PreparedStatement时 应用场景:参数加密、参数验证、参数默认值设置等。

  4. ResultSetHandler:结果集处理器,可拦截:

    • handleResultSets():处理ResultSet生成结果对象时

    • handleOutputParameters():处理存储过程输出参数时 应用场景:结果集解密、结果集增强、懒加载触发等。

四、插件实现原理:JDK动态代理的责任链模式

MyBatis插件的实现原理相当优雅,它结合了JDK动态代理和责任链模式:


具体实现步骤:

  1. 插件定义:开发者实现Interceptor接口,定义拦截逻辑:

     @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})public class MyPlugin implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 前置处理System.out.println("Before method: " + invocation.getMethod().getName());// 执行原始方法Object result = invocation.proceed();// 后置处理System.out.println("After method: " + invocation.getMethod().getName());return result;}}
  2. 代理包装:MyBatis启动时,会通过Plugin.wrap()方法,使用JDK动态代理为目标对象创建代理: 

    public static Object wrap(Object target, Interceptor interceptor) {// 创建代理对象,将所有方法调用路由到interceptor.intercept()return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new Plugin(target, interceptor));}
  3. 责任链构建:当有多个插件时,MyBatis会构建一个代理链:

     // 伪代码:多个插件的包装过程Object target = new SimpleStatementHandler(...);target = Plugin.wrap(target, plugin1);target = Plugin.wrap(target, plugin2);target = Plugin.wrap(target, plugin3);// 最终使用的target已经是经过三层代理的对象
  4. 方法拦截:当调用代理对象的方法时,会触发Plugin.invoke(),进而调用插件的intercept()方法。在intercept()中,开发者可以决定是否继续调用invocation.proceed()来执行链中的下一个拦截器或最终的目标方法。

五、总结与展望

通过本阶段的开发,我们不仅实现了一个功能完整的ORM框架,更重要的是理解了MyBatis架构演进的思路:从核心功能实现,到职责分离优化,再到通过插件机制提供扩展性。

插件机制是MyBatis架构中最精妙的设计之一,它体现了"开放-封闭原则"(对扩展开放,对修改关闭)的精髓。通过动态代理和责任链模式的结合,MyBatis提供了一个极其灵活且强大的扩展机制。

在接下来的文章中,我们将深入探讨:

  1. 如何实现一个完整的插件系统

  2. 事务管理的深度集成

  3. 缓存机制的设计与实现

  4. 动态SQL的解析与处理

每一次的架构优化都是为了更好地应对未来的需求变化,这也是软件设计的永恒追求。我们的手写MyBatis之旅,不仅是在"造轮子",更是在深入理解优秀框架背后的设计哲学和实现原理。


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

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

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

http://www.xdnf.cn/news/19229.html

相关文章:

  • Shell脚本编程入门:从基础语法到流程控制
  • USB4 vs USB3.0:一场接口技术的革命性飞跃
  • 鸿蒙ArkTS 核心篇-14-条件表达式(三目运算符)
  • 如何提高微型导轨的生产效率?
  • 使用 Visio Viewer 查看 Visio 绘图文件
  • 语义分割一站式到底怎么玩?
  • 中级统计师-统计实务-第三章 国民经济核算
  • 智能装备如何与软件结合?
  • MySQL独占间隙锁为什么会互相兼容?
  • 慢SQL优化
  • SQL 学习
  • 以声为剑,绘山河热血——刘洋洋《不惧》8月30日全网上线
  • 逆向思维下,如何把基金投资做亏?
  • 算法 --- 前缀和
  • 一文了解大模型微调
  • AWD相关知识
  • 【Python】国内可用的高速pip镜像源大全
  • 蓝牙5.3核心技术架构解析:从控制器到主机的无线通信设计
  • 知识随记-----Qt 样式表深度解析:何时需要重写 paintEvent 让 QSS 生效
  • 鸿蒙ArkTS 核心篇-15-条件渲染(组件)
  • 如何改变传统教育的消费习惯-第三代结束-第四代开启
  • 源码解析-时间轮[HashedWheelTimer]
  • 项目管理方法如何选择
  • Python实现京东商品数据自动化采集的实用指南
  • 水库/油箱/化工罐区...无线液位控制系统如何实现远程监控?
  • C++ constexpr:编译时计算的高效秘籍
  • 动态规划--Day05--最大子数组和--53. 最大子数组和,2606. 找到最大开销的子字符串,1749. 任意子数组和的绝对值的最大值
  • 音视频学习(六十):H264中的PPS
  • 基于Kubernetes Operator的自动化运维平台设计与实践
  • Ethan开发者创新项目日报 | 2025-08-30