mybatis的插件机制
一、mybatis的插件介绍
关于mybatis的插件,我想大家也都用过,就比如最常用的逆向工程,根据表结构生成model,dao,xml文件,还有分页插件,那这些插件的工作原理是怎么样的呢,就比如分页插件,它为什么能改变我们在xml文件中写的sql语句,本文将带大家一起来了解mybatis的插件机制。(由于本人也是在不断学习,文中难免有错误或不足之处,还望指正,本文基于mybatis3.3.0版本),下面将围绕这几个方面
1、插件入口,即怎么把插件注入到mybatis代码里面
2、插件能拦截哪些类或哪些方法
3、举例简易分表插件原理
二、插件入口
在先了解前,我们来一段自定义mybatis插件的代码
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*; import java.sql.Connection;
import java.util.Properties; @Intercepts(
value = {
@Signature(
type = StatementHandler.class,
method = "prepare",
args = {Connection.class} // 不同版本的prepare方法参数不一样,高版本的还有一个Integer参数
)
}
)
public class PluginDemo implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
return invocation.proceed();
} @Override
public Object plugin(Object target) {
return Plugin.wrap(target,this);
} @Override
public void setProperties(Properties properties) { }
要自定义mybatis插件,必须得实现Interceptor接口,这个接口有三个抽象方法
1、intercept,这个方法是mybatis的核心方法,要实现自定义逻辑,基本都是改造这个方法,其中invocation参数可以通过反射要获取原始方法和对应参数信息
2、plugin,它的作用是用来生成一个拦截对方,也就是代理对象,使得被代理的对象一定会经过intercept方法,通常都会使用mybatis提供的工具类Plugin来获取代理对象,如果有自己独特需求,可以自定义
3、setProperties,这个方法就是用来设置插件的一些属性
其中@intercepts注解就是用来标明拦截哪些类,哪些方法。
当我们脱离spring容器来使用mybatis的时候,我们通常是这样写代码的

而在mybatisConfig.xml文件中,我们有配置数据库连接信息,插件,别名,mapper文件映射地址等信息,(温馨提示,这些配置有一定顺序,如果不按照顺序配置,则mybatis解析时会抛出异常,详细配置信息可以参考mbatis的dtd文件配置)既然在配置文件中配置了,那肯定也会被解析掉,如下图,在XmlConfigBuild中进行解析

解析后,插件信息会被存储到configuation中InterceptorChain集合里面,这个configuation在mybatis运行周期是一个单例的,它负责存储所有的配置信息

最终,mybatis的插件信息完整的注入到了configuation里面。
二、mybaits插件能拦截哪些类或哪些方法
在正常开发流程中,我们基本都是通过先获取sqlSession,如果不采用自定义配置,在默认的sqlsession实现就是defaultSqlSession,在该类的一个方法里就隐含了融合插件,

其中会获取到executor,这个类是通过configuation获取的,

最终融合插件的方法就是图中红框的代码。它会为原始的executor类生成代理类。从而你在执行executor类的一些方法时,比如query,update方法,会先生成对应的代理对象,myabtis采用的是jdk的动态代理,代理后,你执行executor类的query,update方法时会自动转接到你自定义的插件intercept方法里面,也可以理解为覆盖原来的方法。
通过这,我们大概也可以猜测的出,mybatis插件要拦截的类,很大原因在configuation类中有生成,也不带大家绕弯子了,来看截图
拦截statementHandler接口的实现类,它通过routingStatementHandler来实现路由,最终定向到prepareStatementHandler类

拦截parameterHandler。这个接口是用来封装参数用的,也就是最终将参数设置到sql里面

拦截ResultSetHandler接口,它主要用于处理sql运行返回的结果

总结,mybatis可以拦截的类分四大类
一、executor,executor类可以说是执行sql的全过程,如组装参数,sql改造,结果处理,比较广泛,但实际用的不多
二、StatementHandler,这个是执行sql的过程,可以获取到待执行的sql,可用来改造sql,如分页,分表,最常拦截的类
三、paremeterHandler,这个用来拦截sql的参数,可以自定义参数组装规则
四、resultHandler,这个用来处理结果
三、简易版分表插件
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject; import java.sql.Connection;
import java.util.Properties; @Intercepts(
value = {
@Signature(
type = StatementHandler.class,
method = "prepare",
args = {Connection.class}
)
}
)
public class PluginDemo implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable { /**
* 获取被拦截的目前类,在这里是拦截了statementHandler,所有目前类也就是它
* 通过这个类我们可以拿到待执行的sql语句,通常使用mataObject工具类来获取
* 关于这个工具类,大家可自行了解,个人认为这个工具类很强大
*/
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
/**
* 先解释下为什么写成delegate.boundSql就可以拿到boundSql类
* 从前面也可以得知,statementHandler的默认实现是routingStatementHandler。
* 这个类有一个属性statementHandler,属性名就叫delegate,而这个属性的默认实现又是preparedStatementHandler
* 后面这个类又有属性boundSql,所以,最终形成的写法就是delegate.boundSql。
* 所以这也体现了MetaObject工具类的强大,可以通过实例传参,就可以根据属性名获取对应属性值
*/
BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql"); // 待执行的sql,在这里也就是预编译后的sql,即参数位都是?号
String sql = boundSql.getSql();
/**
* 既然拿到了预编译后的sql,那就可以按照你自己的想法为所欲为,如分页,按年分表等等
* 分表的话,个人推荐druid的sql解析器,我认为还是不错的,大家可以自行了解
* 最后改造完sql,别忘了把它设置回去
* metaObject.setValue("delegate.boundSql.sql",sql);
* invocation.proceed,即原始方法的执行
* 注意点就是,因为mybatis插件采用的是代理模式,所以如果存在多个插件,会形成多个代理
* 你如果要拿到最原始的对象,还得进一步进行分解
* 如:while(metaObject.getValue(""h) != null){
* Object obj = metaObject.getValue("h");
* ....
* }
*/
return invocation.proceed();
} @Override
public Object plugin(Object target) {
return Plugin.wrap(target,this);
} @Override
public void setProperties(Properties properties) { }
}
-----------------------------------------------------------------------------------------------------------------------------分界线-------------------------------------------------------------------------------------
以上就是全部内容
mybatis的插件机制的更多相关文章
- mybatis插件机制
目录 mybatis插件机制 主要 类/接口 和 方法 mybatis插件机制实现 mybatis插件机制 mybatis的插件机制使用动态代理实现,不了解的朋友请先了解代理模式和动态代理:插件本质是 ...
- MyBatis 源码分析 - 插件机制
1.简介 一般情况下,开源框架都会提供插件或其他形式的拓展点,供开发者自行拓展.这样的好处是显而易见的,一是增加了框架的灵活性.二是开发者可以结合实际需求,对框架进行拓展,使其能够更好的工作.以 My ...
- 精尽MyBatis源码分析 - 插件机制
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- 一、mybatis的插件介绍
摘自:https://www.cnblogs.com/qm-article/p/11785350.html mybatis的插件机制 一.mybatis的插件介绍 关于mybatis的插件,我想大 ...
- mybatis插件机制及分页插件原理
MyBatis 插件原理与自定义插件: MyBatis 通过提供插件机制,让我们可以根据自己的需要去增强MyBatis 的功能.需要注意的是,如果没有完全理解MyBatis 的运行原理和插件的工作方式 ...
- mybatis(六)插件机制及分页插件原理
转载:https://www.cnblogs.com/wuzhenzhao/p/11120848.html MyBatis 通过提供插件机制,让我们可以根据自己的需要去增强MyBatis 的功能.需要 ...
- MyBatis(八):MyBatis插件机制详解
MyBatis插件插件机制简介 MyBatis插件其实就是为使用者提供的自行拓展拦截器,主要是为了可以更好的满足业务需要. 在MyBatis中提供了四大核心组件对数据库进行处理,分别是Exec ...
- mybatis插件机制原理
mybatis插件机制及分页插件原理 参考链接:mybatis插件机制及分页插件原理 如何编写一个自定义mybatis插件 参考链接:mybatis 自定义插件的使用
- 关于struts2的过滤器和mybatis的插件的分析
网上一搜,发现一篇写的非常棒的博文,就直接复制过来了,供以后复习使用. 前辈博文链接:共三篇: http://jimgreat.iteye.com/blog/1616671: http://jimgr ...
随机推荐
- electron教程(二): http服务器, ws服务器, 进程管理
我的electron教程系列 electron教程(一): electron的安装和项目的创建 electron教程(二): http服务器, ws服务器, 进程管理 electron教程(三): 使 ...
- linux常用开发命令总结
linux常用命令 文件操作命令 1. cd 目录名/目录名 切换目录 cd .. 切换到上一级目录 (change dictionary) Ctrl+C强制退出命令行,回到上一级 2.ls ...
- Spring Cloud Stream 整合 RabbitMQ
简介 Spring Cloud Stream是一个构建消息驱动微服务的框架,应用程序通过input(相当于consumer).output(相当于producer)来与Spring Cloud Str ...
- Google资深工程师深度讲解Go语言★
课程目录 第1章 课程介绍 第2章 基础语法 第3章 内建容器 第4章 面向“对象” 第5章 面向接口 第6章 函数式编程 第7章 错误处理和资源管理 第8章 测试与性能调优 第9章 Goroutin ...
- 【php中的curl】php中curl的详细解说
本文我来给大家详细介绍下cURL的简单的使用方法,下文我将会给大家详细介绍cURL的高级应用, cURL可以使用URL的语法模拟浏览器来传输数据, FTP, FTPS, HTTP, HTTPS, GO ...
- 手把手教你如何在Windows下allure与jenkins的集成生成让你一见钟情的测试报告 - 03(非常详细,非常实用)
简介 好了,国庆假期结束,开始搬砖.为什么要把allure和jenkins集成了?原因是集成以后,我们就可以直接查看allure的结果,不需要重复输入命令.重复使用浏览器打开文件来查看allure的结 ...
- ShaderHelper2 组件升级,支持自动枚举参数!
ShaderHelper2 组件新体验视频演示: https://www.bilibili.com/video/av69314195/ ShaderHelper2 组件我们已经介绍过两次了,不了解的伙 ...
- Flutter学习笔记(29)--Flutter如何与native进行通信
如需转载,请注明出处:Flutter学习笔记(29)--Flutter如何与native进行通信 前言:在我们开发Flutter项目的时候,难免会遇到需要调用native api或者是其他的情况,这时 ...
- React入门学习
为了获得更好的阅读体验,请访问原地址:传送门 一.React 简介 React 是什么 React 是一个起源于 Facebook 的内部项目,因为当时 Facebook 对于市场上所有的 JavaS ...
- The Troublesome Frog
In Korea, the naughtiness of the cheonggaeguri, a small frog, is legendary. This is a well-deserved ...