插件
根据功能,可以将插件分为两大类:
-
第一类:插件是对系统的一种补充,例如在分布式系统中,可以使用插件的方式,实现内存插件、磁盘插件、线性网络插件、Paxos插件等。此类插件等同于组件。
-
第二类:插件是对系统默认功能的自定义修改,例如mybatis里面自定义插件,它实现的拦截器的功能。此类插件等同于拦截器。
MyBatis拦截器插件
mybatis里面自定义插件属于拦截器插件,大凡拦截器(Interceptor)都需要关注两个要点:
- 拦截的对象是谁,用代码行话来说,target目标是谁?
- 拦截的技术方案是什么?
拦截的对象
我们知道,MyBatis有四大核心对象:
- ParameterHandler:处理SQL的参数对象
- ResultSetHandler:处理SQL的返回结果集
- StatementHandler:数据库的处理对象,用于执行SQL语句
- Executor:MyBatis的执行器,用于执行增删改查操作
那么,MyBatis拦截器针对的对象就是上面“四大金刚”。
拦截的技术方案
在Java里面,我们想拦截某个对象,只需要把这个对象包装一下,用代码行话来说,就是重新生成一个代理对象。
下面,我们将代理对象成为 “变身”、将原生对象称为 “原生”
也就是说,一旦配置上插件,ParameterHandler,ResultSetHandler,StatementHandler,Executor这四大核心对象,将会生成 “变身”,是一种代理对象,而不再是 “原身”。
MyBatis拦截器插件整个运行过程
没有插件的运行过程
有插件的运行过程
可以可以理解了吧?
一旦配置上插件,ParameterHandler,ResultSetHandler,StatementHandler,Executor这四大核心对象,将会生成 “变身”,是一种代理对象,而不再是 “原身”。
时序图
下面时序图更加清晰反映情况,
如下是时序图,在整个时序图中,涉及到mybatis插件部分已标红,基本上就是体现在上文中提到的四个类上,对这些类上的方法进行拦截。
运行过程详细的实现机制
实现分三步:插件配置信息的加载、代理对象的生成、拦截逻辑的执行
插件配置信息的加载
假设是基于xml配置,有如下配置
<plugins>
<plugin interceptor="org.apache.ibatis.builder.ExamplePlugin">
<property name="plubinProperty" value="100">
</plugin>
</plugins>
自定义MyBatis拦截器插件
自定义拦截器定位到目标需要指明两点:
- 拦截的对象
- 拦截的方法(包括参数)
然后就是前面讲的流程实现
- 插件配置信息的加载
- 代理对象的生成
- 拦截逻辑的执行
mybatis均提供了接口方法,让我们自定义。
于是,我们自定义mybatis拦截器插件,实质上就是需要把上面5个点给实现了。
拦截的对象和方法
可以拦截的对象也就那四大对象,每个对象有各自可以拦截的方法:
- 执行器Executor(update、query、commit、rollback等方法);
- 参数处理器ParameterHandler(getParameterObject、setParameters方法);
- 结果集处理器ResultSetHandler(handleResultSets、handleOutputParameters等方法);
- SQL语法构建器StatementHandler(prepare、parameterize、batch、update、query等方法);
参考: