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

MyBatisPlus插件原理

MyBatis作为一款优秀的持久层框架,其插件机制为开发者提供了强大的扩展能力。无论是实现SQL日志打印、分页查询,还是数据脱敏、权限控制,都可以通过插件轻松搞定。

一、MyBatis插件的本质:拦截四大核心接口

MyBatis插件的核心思想是"拦截"——在SQL执行的关键节点插入自定义逻辑。而这些关键节点,正是由MyBatis的四个核心接口及其方法构成。

为什么是这四个接口?

可以把MyBatis执行SQL的过程想象成一条"生产流水线",而这四个接口就是流水线上的四个关键工位,负责SQL执行的全流程:

核心接口作用(类比工厂工位)核心方法
Executor执行器(总指挥):负责SQL执行的整体调度,包括查询、更新、事务管理等query()update()commit()
StatementHandlerSQL处理器(执行者):负责与数据库交互,创建Statement对象、执行SQLprepare()parameterize()query()
ParameterHandler参数处理器:负责给SQL中的占位符设置参数(Java对象→数据库类型)setParameters()
ResultSetHandler结果集处理器:负责将数据库返回的结果集转换为Java对象handleResultSets()

这四个接口覆盖了SQL执行的完整生命周期:从接收请求、处理参数、执行SQL到转换结果。插件只有拦截这些接口的方法,才能在关键节点插入自定义逻辑。

二、动态代理:插件实现的"黑科技"

知道了要拦截哪些接口,接下来的问题是:MyBatis如何实现"拦截"?
答案是JDK动态代理

用生活案例理解动态代理

想象你去租房的场景:

  • 你(调用者)想找房东(目标对象)租房(原方法)
  • 但你通过中介(代理对象)沟通,中介会先帮你筛选房源、议价(拦截逻辑)
  • 最后中介再联系房东完成租房(执行原方法)

在这个过程中,你没有直接接触房东,但中介悄悄在租房流程中加入了额外操作。这就是动态代理的核心思想:不修改原对象的前提下,通过代理对象在方法执行前后插入自定义逻辑

MyBatis中的代理实现

MyBatis插件的工作流程与租房案例高度相似:

  1. 定义拦截逻辑:开发者编写插件类,指定要拦截的接口和方法(比如拦截StatementHandlerprepare()方法)
  2. 创建代理对象:MyBatis启动时,会为四大接口的实现类创建代理对象(通过JDK动态代理)
  3. 执行拦截流程
    • 当MyBatis调用目标方法(如statementHandler.prepare())时,实际调用的是代理对象的方法
    • 代理对象先执行插件中的拦截逻辑(如记录SQL执行开始时间)
    • 再调用原对象的方法,执行真正的SQL操作
    • 最后执行插件中的后续逻辑(如计算SQL执行耗时)

通过这种方式,插件既不会修改MyBatis的核心代码,又能灵活地插入自定义逻辑。

三、实战案例:编写一个SQL执行时间监控插件

我们通过一个实际案例感受插件的工作机制。假设我们需要监控每条SQL的执行时间,步骤如下:

1. 编写插件类(实现Interceptor接口)

@Intercepts({@Signature(type = StatementHandler.class,  // 要拦截的接口method = "prepare",             // 要拦截的方法args = {Connection.class, Integer.class}  // 方法参数)
})
public class SqlExecutionTimePlugin implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 1. 执行拦截逻辑(记录开始时间)long startTime = System.currentTimeMillis();try {// 2. 执行原方法(让MyBatis继续处理SQL)return invocation.proceed();} finally {// 3. 执行后续逻辑(计算耗时)long endTime = System.currentTimeMillis();long cost = endTime - startTime;// 获取当前执行的SQLStatementHandler statementHandler = (StatementHandler) invocation.getTarget();BoundSql boundSql = statementHandler.getBoundSql();String sql = boundSql.getSql();System.out.println("SQL执行耗时:" + cost + "ms,SQL语句:" + sql);}}// 创建代理对象(固定写法)@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}// 设置插件属性(可在mybatis-config.xml中配置)@Overridepublic void setProperties(Properties properties) {// 可读取配置参数,如设置超时阈值等}
}

2. 配置插件(在mybatis-config.xml中注册)

<configuration><plugins><plugin interceptor="com.example.SqlExecutionTimePlugin"><!-- 可配置插件属性 --></plugin></plugins>
</configuration>

3. 执行效果

当MyBatis执行SQL时,插件会自动打印执行时间:

SQL执行耗时:15ms,SQL语句:SELECT * FROM user WHERE id = ?

四、插件开发注意事项

  1. 拦截范围:插件只能拦截四大核心接口的方法,不可自定义其他接口
  2. 性能影响:避免在插件中编写耗时操作,否则会影响SQL执行效率
  3. 顺序问题:多个插件时,执行顺序由配置顺序决定(先配置的先执行)
  4. 兼容性:过度依赖内部实现可能导致升级MyBatis时出现问题

五、总结

MyBatis插件通过"拦截四大核心接口+JDK动态代理"的方式,实现了对SQL执行流程的灵活扩展。其本质是:

  • 以四大接口为切入点,覆盖SQL执行全流程
  • 用动态代理机制在方法执行前后插入自定义逻辑
  • 不侵入核心代码,却能实现强大的扩展功能

插件的核心不是"修改",而是"增强"——在不破坏原有逻辑的前提下,优雅地扩展功能。

http://www.lryc.cn/news/616377.html

相关文章:

  • Leetcode 3646. Next Special Palindrome Number
  • 代码随想录算法训练营第六十天|图论part10
  • 【Nginx②】 | Nginx部署前端静态文件指南(基于虚拟机环境)
  • 浏览器CEFSharp88+X86+win7 之多页面展示(四)
  • NodeJs学习日志(4):路由合并_环境配置_常用文件目录
  • element-ui el-progress在有小数的情况下,会换行显示。解决不换行的问题。
  • iceberg安装部署
  • Rust面试题及详细答案120道(11-18)-- 控制流与函数
  • vulnhub-Drippingblues靶机
  • 通过Certbot自动申请更新HTTPS网站的SSL证书
  • 瑞芯微 RK3588 平台驱动开发 学习计划
  • CST支持对哪些模型进行特征模仿真?分别有哪些用于特征模分析的求解器?
  • C语言——深入理解指针(二)
  • 【东枫科技】FR3 可扩展测试平台,适用于 6G 研究与卫星通信,高达 1.6 GHz 的带宽
  • 【秋招笔试】2025.08.09美团秋招算法岗机考真题-第三题
  • Python 的浅拷贝 vs 深拷贝(含嵌套可变对象示例与踩坑场景)
  • OpenGL VAO 概念、API 和示例
  • 每日一题:使用栈实现逆波兰表达式求值
  • TypeScript中的type和interface的区别是什么?
  • 从街亭失守看管理
  • WAV音频数据集MFCC特征提取处理办法
  • 【MySQL——第三章 :MySQL库表操作】
  • 如何选择适合自己电商业务的 API?​
  • DBAPI 实现不同角色控制查看表的不同列
  • 七、CV_模型微调
  • 使用快捷键将当前屏幕内容滚动到边缘@首行首列@定位到第一行第一个字符@跳转到4个角落
  • Knuth‘s TwoSum Algorithm 原理详解
  • 每日任务day0810:小小勇者成长记之武器精炼
  • 机器学习 DBScan
  • VUE+SPRINGBOOT从0-1打造前后端-前后台系统-关于我们