插件原理与开发
插件原理与开发
在 Mybatis总体执行流程 一文中简单的介绍了插件的初始化过程,本文将从源码的角度介绍一下mybatis的插件原理与简单开发实战。
插件原理
插件的注册和管理是通过InterceptorChain进行的,在创建Executor、StatementHandler、ParameterHandler、ResultSetHandler对象时,会执行InterceptorChain的pluginAll方法
public Object pluginAll(Object target) {// 遍历所有的插件for (Interceptor interceptor : interceptors) {// 执行插件的plugin方法,返回代理对象target = interceptor.plugin(target);}return target;}
拦截的原理,正是此时返回的代理对象,当调用目标方法时,执行的就是拦截器的intercept方法,从而实现拦截功能。
// 执行插件的plugin方法,返回代理对象target = interceptor.plugin(target);
来到Interceptor接口的plugin方法:
default Object plugin(Object target) {return Plugin.wrap(target, this);}
这是一个默认方法,一般不会重写它的逻辑。看其实现Plugin#wrap:
public static Object wrap(Object target, Interceptor interceptor) {// 拿到拦截器的@Intercepts注解信息:key是要拦截的接口,value是要拦截的接口方法集合Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);// 这里的target,就是拦截的对象(Executor、StatementHandler、ParameterHandler、ResultSetHandler对象)Class<?> type = target.getClass();// 返回包含在signatureMap中的接口Class<?>[] interfaces = getAllInterfaces(type, signatureMap);// 存在被拦截的接口,返回一个代理对象if (interfaces.length > 0) {// 利用jdk动态代理生成代理对象:关注Plugin(实现了InvocationHandler接口)的invoke方法return Proxy.newProxyInstance(type.getClassLoader(),interfaces,new Plugin(target, interceptor, signatureMap));}// 接口没有被拦截,返回原始对象return target;}
可以看到,如果接口被拦截了,就会利用JDK动态代理生成代理对象,由于Plugin实现了InvocationHandler接口,所以其invoke方法会被执行:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {// 拿到被拦截的接口方法集合Set<Method> methods = signatureMap.get(method.getDeclaringClass());// 判断当前执行的方法是否包含在其中,包含就是被拦截的方法if (methods != null && methods.contains(method)) {// 执行自定义拦截器的intercept方法,并将目标对象、方法、参数传入return interceptor.intercept(new Invocation(target, method, args));}// 否则直接执行原始方法return method.invoke(target, args);} catch (Exception e) {throw ExceptionUtil.unwrapThrowable(e);}}
插件开发
自定义插件需要:
-
实现Interceptor接口,重写intercept方法
-
使用@Intercepts和@Signature注解表明需要拦截哪些类的哪些方法
-
在配置文件中,添加插件配置
mybatis官网中,对此也有所描述:mybatis – MyBatis 3 | Configuration
根据官网描述,mybatis插件可以拦截的方法如下:
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
以下是我写的一个记录SQL及其耗时的拦截器,加深对拦截器的理解:
/*** @Author: qiuxinfa* @CreateTime: 2023-12-07 22:15* @Description: 自定义拦截器:打印SQL、统计SQL执行时间*/
@Intercepts({@Signature(type = StatementHandler.class,method = "batch",args = {Statement.class}),@Signature(type = StatementHandler.class,method = "update",args = {Statement.class}),@Signature(type = StatementHandler.class,method = "query",args = {Statement.class, ResultHandler.class}),
})
public class SqlLogPlugin implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 获取执行的SQLString sql;Statement statement=(Statement) invocation.getArgs()[0];if(Proxy.isProxyClass(statement.getClass())){MetaObject metaObject= SystemMetaObject.forObject(statement);Object h = metaObject.getValue("h");if(h instanceof StatementLogger){RoutingStatementHandler rsh=(RoutingStatementHandler) invocation.getTarget();sql = rsh.getBoundSql().getSql();}else {PreparedStatementLogger psl=(PreparedStatementLogger) h;sql = psl.getPreparedStatement().toString();}}else{sql = statement.toString();}// 记录开始时间long start = System.currentTimeMillis();// 执行目标方法Object result = invocation.proceed();// 记录结束时间long end = System.currentTimeMillis();System.err.println("执行SQL ===> ");System.err.println(sql);System.err.println("统计SQL耗时 = " + (end - start) + "毫秒");System.err.println("返回结果 =======> " + result);return result;}
}
配置文件添加插件:
<!-- 配置插件 --><plugins><plugin interceptor="com.qxf.plugin.SqlLogPlugin"></plugin></plugins>
配置之后,会打印执行的SQL语句及其耗时。
相关文章:
插件原理与开发
插件原理与开发 在 Mybatis总体执行流程 一文中简单的介绍了插件的初始化过程,本文将从源码的角度介绍一下mybatis的插件原理与简单开发实战。 插件原理 插件的注册和管理是通过InterceptorChain进行的,在创建Executor、StatementHandler、ParameterH…...
Git 分支合并时 Merge, Rebase, Squash 的使用场景
前言 Git 的分支设计大大提升了并行开发的能力,但相应的,也就要解决如何进行分支合并。毕竟分久必合,最终还是要把大家的工作合并起来,进行统一发布的。在合并时,通常有三种操作: Merge commitsRebaseSqu…...
第5节:Vue3 JavaScript 表达式
在 Vue3 中,JavaScript 表达式的使用方式与 Vue2 有所不同。 在 Vue3 中,你可以使用 v-bind 指令来绑定 JavaScript 表达式。例如: <template><div>{{ count }}</div> </template><script> import { ref } f…...
StarRocks 存算分离最佳实践,让降本增效更简单
StarRocks 存算分离自版本 3.0.0 开放使用,已经历过多个大版本迭代,在众多客户生产环境中得到验证。但在用户使用过程中也反馈了一些问题,大多源自对新能力不够熟悉导致无法达到最佳效果。因而,本文提供 StarRocks 存算分离最佳实…...
虚拟网络技术:bond技术
网卡bond也称为网卡捆绑,就是将两个或者更多的物理网卡绑定成一个虚拟网卡。 bond的作用: 1.提高网卡的吞吐量 2.增加网络的高可用,实现负载均衡。 一、bond简介 bond技术即bonding,能将多块物理网卡绑定到一块虚拟网卡上&…...
【Android】解决安卓中并不存在ActivityMainBinding
安卓中并不存在ActivityMainBinding这个类,这个类是在XML布局的最外层加入就会自动生成。但是你在最后绑定主布局时会报错获取不到根节点getRoot(). 最好的办法就是,删除原来的最外层节点,再重新添加,感觉是因为复制时并没有让系…...
mysql的几种索引
mysql索引的介绍可以mysql官网的词汇表中搜索: https://dev.mysql.com/doc/refman/8.0/en/glossary.html mysql可以在表的一列、或者多列上创建索引,索引的类型可以选择,如下: 普通索引(KEY) 普通索引可…...
R语言手册30分钟上手
文章目录 1. 环境&安装1.1. rstudio保存工作空间 2. 创建数据集2.1. 数据集概念2.2. 向量、矩阵2.3. 数据框2.3.1. 创建数据框2.3.2. 创建新变量2.3.3. 变量的重编码2.3.4. 列重命名2.3.5. 缺失值2.3.6. 日期值2.3.7. 数据框排序2.3.8. 数据框合并(合并沪深300和中证500收盘…...
前缀和例题:子矩阵的和AcWing796-Java版
//前缀和模板提,在读入数据的时候就可以先算好前缀和的大小 //计算前缀的时候用:g[i][j] g[i][j-1] g[i-1][j] - g[i-1][j-1] Integer.parseInt(init[j-1]); //计算结果的时候用:g[x2][y2] - g[x1 - 1][y2]- g[x2][y1-1] g[x1 -1][y1 - 1] "\n" //一些重复加的地…...
前端传参中带有特殊符号导致后端接收时乱码或转码失败的解决方案
文章目录 bug背景解决思路1:解决思路2解决思路3(最终解决方案)后记 bug背景 项目中采用富文本编辑器后传参引起的bug,起因如下: 数据库中存入的数据会变成这种未经转码的URL编码 解决思路1: 使用JSON方…...
【扩散模型】深入理解图像的表示原理:从像素到张量
【扩散模型】深入理解图像的表示原理:从像素到张量 在深度学习中,图像是重要的数据源之一,而图像的表示方式对于算法的理解和处理至关重要。本文将带你深入探讨图像的底层表示原理,从像素到张量,让你对图像表示有更清…...
WPS论文写作——公式和公式序号格式化
首先新建一个表格,表格尺寸按你的需求来确定,直接 插入--》表格 即可。 然后在表格对应位置填上公式(公式要用公式编辑器)和公式序号,然后可以按照单独的单元格或者整行或整列等来设置样式,比如居中对齐、…...
ChatGPT一周年,奥特曼官宣 OpenAI 新动作!
大家好,我是二狗。 今天是11月30日,一转眼,ChatGPT 发布已经一周年了! 而就在刚刚,ChatGPT一周年之际。 OpenAI 正式宣布Sam Altman回归重任CEO, Mira Murati 重任CTO,Greg Brockman重任总裁,O…...
JVM 运行时内存篇
面试题: 讲一下为什么JVM要分为堆、方法区等?原理是什么?(UC、智联) JVM的分区了解吗,内存溢出发生在哪个位置 (亚信、BOSS) 简述各个版本内存区域的变化࿱…...
Docker安装postgres最新版
1. postgres数据库 PostgreSQL是一种开源的关系型数据库管理系统(RDBMS),它是一种高度可扩展的、可靠的、功能丰富的数据库系统。以下是关于PostgreSQL的一些介绍: 开源性:PostgreSQL是一个开源项目,可以…...
浅析计算机网络安全的的防范与措施
摘 要 随着信息和通讯的高速发展使得人们对计算机的依赖逐渐增强,生活与工作当中计算机都担任着那个不可或缺的角色,已经是人们生活当中的一部分,充分影响着我们生活和工作中的很多关键点,但计算机过多地在工作和生活中使用也带来…...
多表操作、其他字段和字段参数、django与ajax(回顾)
多表操作 1 基于对象的跨表查 子查询----》执行了两句sql,没有连表操作 2 基于双下滑线的连表查 一次查询,连表操作 3 正向和反向 放在ForeignKey,OneToOneField,ManyToManyField的-related_namebooks:双下滑线连表查询,反向…...
您知道计算机是怎么分类的嘛
地表最强计算机 第 61 版全球最强大的超级计算机已经发布。名为 Top500,顾名思义,该列表列出了全球 500 台最强大的超级计算机。榜单显示,美国的AMD、英特尔和IBM处理器是超级计算系统的首选。在 TOP10 中,有四个系统使用 AMD 处理…...
[MTK]安卓8 ADB执行ota升级
需求 adb 推送update.zip进行安卓的OTA升级 环境 平台:mtk SDK:Android 8 命令方式 需要root adb root adb remount adb push update.zip /data/media/0/ adb shell uncrypt /data/media/0/update.zip /cache/recovery/block.map adb shell echo /data/media/0/update.zi…...
python-比较Excel两列数据,并分别显示差异
利用 openpyxl 模块,操作Excel,比较Excel两列数据,并分别显示差异 表格数据样例如下图 A,B两列是需要进行比较的数据(数据源为某网站公开数据);C,D两列是比较结果的输出列 A&#…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
