MyBatis插件机制
MyBatis插件机制是该框架提供的一种灵活扩展方式,允许开发者在不修改框架源代码的情况下对MyBatis的功能进行定制和增强。这种机制主要通过拦截器(Interceptor)实现,使得开发者可以拦截和修改MyBatis在执行SQL语句过程中的行为。
MyBatis允许使用插件来拦截的方法调用包括:
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) 拦截执行器的方法
- ParameterHandler (getParameterObject, setParameters) 拦截参数的处理
- ResultSetHandler (handleResultSets, handleOutputParameters) 拦截结果集的处理
- StatementHandler (prepare, parameterize, batch, update, query) 拦截Sql语法构建的处理
拦截器介绍及配置
MyBatis拦截器的接口定义,plugin方法用于某些处理器(Handler)的构建过程。interceptor方法用于处理代理类的执行。setProperties方法用于拦截器属性的设置:
public interface Interceptor {Object intercept(Invocation invocation) throws Throwable;Object plugin(Object target);void setProperties(Properties properties);}
MyBatis默认没有一个拦截器接口的实现类。下面的MyBatis官网的一个拦截器实例,这个拦截器拦截Executor接口的update方法,所有执行executor的update方法都会被该拦截器拦截到:
@Intercepts({@Signature(type= Executor.class, method = "update", args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {public Object intercept(Invocation invocation) throws Throwable {return invocation.proceed();}public Object plugin(Object target) {return Plugin.wrap(target, this);}public void setProperties(Properties properties) {}
}
<plugins><plugin interceptor="org.format.mybatis.cache.interceptor.ExamplePlugin"></plugin>
</plugins>
源码分析
先从源头->配置文件开始分析:
XMLConfigBuilder解析MyBatis全局配置文件的pluginElement私有方法:
private void pluginElement(XNode parent) throws Exception {if (parent != null) {for (XNode child : parent.getChildren()) {String interceptor = child.getStringAttribute("interceptor");Properties properties = child.getChildrenAsProperties();Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();interceptorInstance.setProperties(properties);configuration.addInterceptor(interceptorInstance);}}
}
public void addInterceptor(Interceptor interceptor) {interceptorChain.addInterceptor(interceptor);
}
InterceptorChain类包含一个Interceptor类型的列表,用于存储拦截器。类中有三个方法:pluginAll()用于将所有拦截器应用于目标对象:
public class InterceptorChain {private final List<Interceptor> interceptors = new ArrayList<Interceptor>();public Object pluginAll(Object target) {for (Interceptor interceptor : interceptors) {target = interceptor.plugin(target);}return target;}public void addInterceptor(Interceptor interceptor) {interceptors.add(interceptor);}public List<Interceptor> getInterceptors() {return Collections.unmodifiableList(interceptors);}}
一开始说的几种方法都会调用pluginAll:
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);return parameterHandler;}public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,ResultHandler resultHandler, BoundSql boundSql) {ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);return resultSetHandler;}public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);return statementHandler;}public Executor newExecutor(Transaction transaction) {return newExecutor(transaction, defaultExecutorType);}public Executor newExecutor(Transaction transaction, ExecutorType executorType) {...executor = (Executor) interceptorChain.pluginAll(executor);return executor;}
由于可以拦截StatementHandler,这个接口主要处理sql语法的构建,因此比如分页的功能,可以用拦截器实现,只需要在拦截器的plugin方法中处理StatementHandler接口实现类中的sql即可,可使用反射实现。
Plugin.wrap方法
Mybatis 中的 Plugin.wrap方法用于生成代理对象,实现对目标对象的增强。在 Mybatis 中,插件是通过动态代理实现的,而 Plugin.wrap方法就是用于创建代理对象的核心方法。
具体来说,Plugin.wrap方法接收两个参数:一个是目标对象(target),另一个是插件实例(plugin)。方法的主要作用是将插件实例和目标对象进行绑定,然后通过动态代理技术生成一个新的代理对象,该代理对象在调用目标对象的方法时,会先执行插件实例中对应的拦截方法(interceptor),从而实现对目标对象的功能增强。
public class Plugin implements InvocationHandler {
private Object target;// 被代理的目标类private Interceptor interceptor;// 对应的拦截器private 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;}}
总结
如果开发者对MyBatis的内部工作原理理解不深,使用拦截器可能会意外改变底层行为,导致难以预料的问题。当使用多个拦截器时,需要仔细管理它们的执行顺序,以确保它们按预期顺序应用,这增加了管理复杂性。同时在编写插件时需注意以下几个原则:
- 不编写不必要的插件
- 实现plugin方法时判断一下目标类型,是本插件要拦截的对象才执行Plugin.wrap方法,否则直接返回,这样可以减少目标被代理的次数。
相关文章:

MyBatis插件机制
MyBatis插件机制是该框架提供的一种灵活扩展方式,允许开发者在不修改框架源代码的情况下对MyBatis的功能进行定制和增强。这种机制主要通过拦截器(Interceptor)实现,使得开发者可以拦截和修改MyBatis在执行SQL语句过程中的行为。 …...
NVIDIA Jetson Linux 35.3.1-开发指南-导言
原文地址:Welcome — Jetson Linux Developer Guide documentation (nvidia.com) 欢迎 本开发人员指南适用于 NVIDIA Jetson Linux版本 35.3.1 GA 。 最后更新: 2023年5月19日 NVIDIA Jetson是世界领先的边缘AI平台。其高性能、低功耗计算 深度学习 ,…...
14. fastLED调色板
Color Palettes Functions and class definitions for color palettes.调色板的函数和类定义。 RGB palettes map an 8-bit value (0-255) to an RGB color. You can create any color palette you wish; a couple of starters are provided: ForestColors_p, CloudColors_p…...

bugku---misc---赛博朋克
1、下载附件解压之后是一个txt文本,查看文本的时候看到头部有NG的字样 2、把txt改为png后缀得到一张图片 3、binwalk没发现奇怪的地方,分离出来还是图片 4、stegslove分析,切换图片没有发现奇怪地方 5、将通道rgb置为0。出现了flag但是flag不…...

vue+elementplus模拟“山野愚人居”简单实现个人博客
目录 一、项目介绍 二、项目截图 1.项目结构图 2.项目首页 3.文章详情 4.留言 5.读者 三、源码实现 1.项目依赖package.json 2.项目启动 3.读者页面源码 四、总结 一、项目介绍 模仿原博客:山野愚人居 - 记录我的生活、所见、所闻、所想…… 本项目参考以…...

ComfyUI 完全入门:Refiner精炼器
在 SDXL基础模型1.0版本发布时,Stability AI 公司同时发布了一个名为SDXL Refiner的模型。这个Refiner模型是专门设计用来对基础模型生成的图像进行进一步优化和细化的,所以大家也经常称之为精炼器或者精修器。 Refiner模型的主要目的是提升图像的质量&…...

FastAPI操作关系型数据库
FastAPI可以和任何数据库和任意样式的库配合使用,这里看一下使用SQLAlchemy的示例。下面的示例很容易的调整为PostgreSQL,MySQL,SQLite,Oracle等。当前示例中我们使用SQLite ORM对象关系映射 FastAPI可以与任何数据库在任何样式…...
数字化那点事:一文读懂智慧城市
一、智慧城市的定义 一个城市信息化发展历程主要包括数字城市、信息城市、智慧城市、互联城市等阶段,现就我们当前所处的智慧城市阶段做个简要介绍。 智慧城市是利用先进的信息和通信技术(ICT)、物联网(IoT)、大数据分…...

RabbitMQ-topic exchange使用方法
RabbitMQ-默认读、写方式介绍 RabbitMQ-发布/订阅模式 RabbitMQ-直连交换机(direct)使用方法 目录 1、概述 2、topic交换机使用方法 2.1 适用场景 2.2 解决方案 3、代码实现 3.1 源代码实现 3.2 运行记录 4、小结 1、概述 topic 交换机是比直连交换机功能更加强大的…...
6-11 函数题:某范围中的最小值
6-11 函数题:某范围中的最小值 分数 5 全屏浏览 作者 雷丽兰 单位 宜春学院 有n(n<1000)个整数,从这n个整数中找到值落在(60至100之间)的最小整数。 函数接口定义: int min ( int arr[], int n); 说明…...

Flask基础2-Jinja2模板
目录 1.介绍 2.模板传参 1.变量传参 2.表达式 3.控制语句 4.过滤器 5.自定义过滤器 6.测试器 7.块和继承 flask基础1 1.介绍 Jinja2:是Python的Web项目中被广泛应用的模板引擎,是由Python实现的模板语言,Jinja2 的作者也是 Flask 的作 者。他的设计思想来源于Django的模…...

Serverless 使用OOS将http文件转存到对象存储
目录 背景介绍 系统运维管理OOS 文件转存场景 前提条件 实践步骤 附录 示例模板 背景介绍 系统运维管理OOS 系统运维管理OOS(CloudOps Orchestration Service)提供了一个高度灵活和强大的解决方案,通过精巧地编排阿里云提供的OpenAPI…...
AcWing 477:神经网络 ← 拓扑排序+链式前向星
【题目来源】https://www.acwing.com/problem/content/479/【题目描述】 人工神经网络(Artificial Neural Network)是一种新兴的具有自我学习能力的计算系统,在模式识别、函数逼近及贷款风险评估等诸多领域有广泛的应用。 对神经网络的研究…...

鲁教版八年级数学下册-笔记
文章目录 第六章 特殊平行四边形1 菱形的性质与判定2 矩形的性质与判定3 正方形的性质与判定 第七章 二次根式1 二次根式2 二次根式的性质3 二次根式的加减二次根式的乘除 第八章 一元二次方程1 一元二次方程2 用配方法解一元二次方程3 用公式法解一元二次方程4 用因式分解法解…...
Web前端栅格:深入解析与实战应用
Web前端栅格:深入解析与实战应用 在Web前端开发中,栅格系统是一种重要的布局工具,它能够帮助我们快速构建响应式、灵活且美观的页面布局。然而,对于许多初学者和从业者来说,栅格系统的概念、原理以及实际应用却常常令…...
mysql Innodb引擎常见问题
问题 1:InnoDB 引擎的主要特点有哪些? 答:支持事务、行级锁、外键约束,具有较好的数据完整性和并发性。 问题 2:InnoDB 如何实现事务的 ACID 特性? 答:通过原子性(事务要么全部成功要…...

创建 MFC DLL-使用关键字_declspec(dllexport)
本文仅供学习交流,严禁用于商业用途,如本文涉及侵权请及时联系本人将于及时删除 从MFC DLL中导出函数的另一种方法是在定义函数时使用关键字_declspec(dllexport)。这种情况下,不需要DEF文件。 导出函数的形式为: declspec(dll…...
机器学习笔记 - 用于3D数据分类、分割的Point Net的网络实现
上一篇,我们大致了解了Point Net的原理,这里我们要进行一下实现。 机器学习笔记 - 用于3D数据分类、分割的Point Net简述-CSDN博客文章浏览阅读3次。在本文中,我们将了解Point Net,目前,处理图像数据的方法有很多。从传统的计算机视觉方法到使用卷积神经网络到Transforme…...
C#知识|基于实体类对象,返回实体集合封装介绍。
哈喽,你好啊,我是雷工! 前面通过实体类封装传递了零散的参数,打包后给数据访问方法。 但当查询结果是数据集,要把查询到的数据返回给UI时,我们也可以把返回的多条零散数据封装到实体类中。 此次练习可以使用实体容器:泛型集合List<T>,当把每条数据封装成实体对…...

关于Redis中哨兵(Sentinel)
Redis Sentinel 相关名词解释 名词 逻辑结构 物理结构 主节点 Redis 主服务 一个独立的 redis-server 进程 从节点 Redis 从服务 一个独立的 redis-server 进程 Redis 数据节点 主从节点 主节点和从节点的进程 哨兵节点 监控 Redis 数据节点的节点 一个独立的 re…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...
libfmt: 现代C++的格式化工具库介绍与酷炫功能
libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库,提供了高效、安全的文本格式化功能,是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全:…...