手写MyBatis第43弹:插件拦截原理与四大可拦截对象详解
🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐是作者创作的最大动力🤞
💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝欢迎留言讨论
🔥🔥🔥(源码 + 调试运行 + 问题答疑)
🔥🔥🔥 有兴趣可以联系我。
我们常常在当下感到时间慢,觉得未来遥远,但一旦回头看,时间已经悄然流逝。对于未来,尽管如此,也应该保持一种从容的态度,相信未来仍有许多可能性等待着我们。
手写MyBatis阶段总结:从CRUD到架构优化,迈向插件开发新征程
MyBatis框架设计深度解析:插件拦截原理与四大可拦截对象详解
从执行器优化到插件机制:手写MyBatis的架构演进与设计思想
MyBatis插件开发完全指南:揭秘Interceptor链的实现原理与应用场景
在我们手写MyBatis的系列旅程中,我们已经成功搭建了一个具备完整CRUD功能的ORM框架雏形。从最初的配置解析、Mapper代理机制,到SQL执行器、参数处理、结果集映射,再到最近的返回值类型适配和Executor职责分离,我们的框架已经完成了从"能用"到"好用"的关键进化。此刻,让我们暂作停留,回顾已实现的核心功能,并前瞻性地探索MyBatis最强大的特性之一——插件机制。
一、阶段成果回顾:我们构建了什么?
我们的迷你MyBatis框架已经具备了现代ORM框架的核心骨架:
完整的CRUD操作:支持通过Mapper接口和SqlSession两种方式执行增删改查,其中增删改操作还能智能适配void、int、boolean等多种返回值类型。
清晰的核心组件协作:各个组件职责分明,形成了精密的协作体系:
优化的架构设计:通过最近的重构,我们实现了关键职责的分离:
连接管理职责移交给了
Transaction
接口Statement创建和执行职责移交给了
StatementHandler
hierarchyExecutor
现在更加专注于执行流程的调度和控制
二、迈向高级特性:为什么需要插件机制?
尽管我们的框架已经功能完备,但在实际企业级应用中,我们经常需要一些横切关注点(Cross-Cutting Concerns)的功能:
SQL性能监控:记录每条SQL的执行时间
分页处理:自动为查询语句添加分页参数
数据权限过滤:根据用户权限自动添加数据过滤条件
SQL改写:优化或调整生成的SQL语句
敏感数据加密/解密:在参数设置和结果获取时进行数据转换
如果将这些功能硬编码到框架核心中,会导致代码臃肿且难以维护。插件机制正是为了解决这个问题而生的——它允许在不修改框架源码的情况下,通过外部插件来扩展和增强框架功能。
三、插件机制深度解析:四大可拦截对象
MyBatis的插件可以拦截四大核心组件的方法执行,这也是插件机制的强大之处:
Executor:这是最常被拦截的对象,可以拦截的方法包括:
update()
:增删改操作的入口query()
:查询操作的入口commit()
、rollback()
:事务相关操作flushStatements()
:批处理操作 应用场景:实现二级缓存、SQL执行时间监控、批量操作优化等。
StatementHandler:SQL语句执行的核心处理器,可拦截:
prepare()
:创建Statement时parameterize()
:设置参数时query()
、update()
:执行SQL时 应用场景:分页插件(改写SQL)、性能监控、参数加密等。
ParameterHandler:参数处理器,可拦截:
setParameters()
:设置参数到PreparedStatement时 应用场景:参数加密、参数验证、参数默认值设置等。
ResultSetHandler:结果集处理器,可拦截:
handleResultSets()
:处理ResultSet生成结果对象时handleOutputParameters()
:处理存储过程输出参数时 应用场景:结果集解密、结果集增强、懒加载触发等。
四、插件实现原理:JDK动态代理的责任链模式
MyBatis插件的实现原理相当优雅,它结合了JDK动态代理和责任链模式:
具体实现步骤:
插件定义:开发者实现
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;}}
代理包装: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));}
责任链构建:当有多个插件时,MyBatis会构建一个代理链:
// 伪代码:多个插件的包装过程Object target = new SimpleStatementHandler(...);target = Plugin.wrap(target, plugin1);target = Plugin.wrap(target, plugin2);target = Plugin.wrap(target, plugin3);// 最终使用的target已经是经过三层代理的对象
方法拦截:当调用代理对象的方法时,会触发
Plugin.invoke()
,进而调用插件的intercept()
方法。在intercept()
中,开发者可以决定是否继续调用invocation.proceed()
来执行链中的下一个拦截器或最终的目标方法。
五、总结与展望
通过本阶段的开发,我们不仅实现了一个功能完整的ORM框架,更重要的是理解了MyBatis架构演进的思路:从核心功能实现,到职责分离优化,再到通过插件机制提供扩展性。
插件机制是MyBatis架构中最精妙的设计之一,它体现了"开放-封闭原则"(对扩展开放,对修改关闭)的精髓。通过动态代理和责任链模式的结合,MyBatis提供了一个极其灵活且强大的扩展机制。
在接下来的文章中,我们将深入探讨:
如何实现一个完整的插件系统
事务管理的深度集成
缓存机制的设计与实现
动态SQL的解析与处理
每一次的架构优化都是为了更好地应对未来的需求变化,这也是软件设计的永恒追求。我们的手写MyBatis之旅,不仅是在"造轮子",更是在深入理解优秀框架背后的设计哲学和实现原理。
💖学习知识需费心,
📕整理归纳更费神。
🎉源码免费人人喜,
🔥码农福利等你领!💖常来我家多看看,
📕我是程序员扣棣,
🎉感谢支持常陪伴,
🔥点赞关注别忘记!💖山高路远坑又深,
📕大军纵横任驰奔,
🎉谁敢横刀立马行?
🔥唯有点赞+关注成!