要想一针见血地理解MyBatis插件机制,只需要明白一点:原身和变身。也就是说,一旦配置上插件,ParameterHandler,ResultSetHandler,StatementHandler,Executor这四大核心对象,将会生成变身,是一种代理对象,而不再是原身。

1、MyBatis插件配置

MyBatis框架的配置文件,即mybatis-config.xml文件中,包括了插件的设置。

mybatis-plugins.png

2、插件的分类

根据功能,可以将插件分为两大类:

第一类:插件是对系统的一种补充,例如在分布式系统中,可以使用插件的方式,实现内存插件、磁盘插件、线性网络插件、Paxos插件等。此类插件等同于组件。

第二类:插件是对系统默认功能的自定义修改,例如mybatis里面自定义插件,它实现的拦截器的功能。此类插件等同于拦截器。

3、MyBatis拦截器插件

mybatis里面自定义插件属于拦截器插件,大凡拦截器都需要关注两个要点:

(1)拦截的对象是谁,用代码行话来说,target目标是谁?
(2)拦截的技术方案是什么?

下面,针对这两个问题进行详细的阐述一下。

3.1、拦截的对象

我们知道,MyBatis有四大核心对象:

(1)ParameterHandler:处理SQL的参数对象
(2)ResultSetHandler:处理SQL的返回结果集
(3)StatementHandler:数据库的处理对象,用于执行SQL语句
(4)Executor:MyBatis的执行器,用于执行增删改查操作

那么,MyBatis拦截器针对的对象就是上面“四大金刚”。

3.2、拦截的技术方案

在Java里面,我们想拦截某个对象,只需要把这个对象包装一下,用代码行话来说,就是重新生成一个代理对象。

mybatis-proxy.png

这样在每次调用Executor类的方法的时候,总是要经过Interceptor接口的拦截。

3.3、拦截对象的变身

一旦我们在mybatis-config.xml里面配置了插件:

<plugins>
    <plugin interceptor="cn.mybatis.MyInterceptor"></plugin>
</plugins>

ParameterHandler,ResultSetHandler,StatementHandler,Executor这“四大金刚”就发生变身,而不再是原身。这个变身的过程是这样的,以ParameterHandler为例:

第一步:根据插件配置,利用反射技术,创建interceptor拦截器

Interceptor interceptor = (Interceptor) MyInterceptor.class.newInstance();

第一步:创建原身
ParameterHandler parameterHandler = createParameterHandler();

第二步:原身+拦截器---->变身
parameterHandler = (ParameterHandler) Plugin.wrap(parameterHandler, interceptor);
在这一步,将parameterHandler和interceptor包装到一起,生成了变身,并重新赋值给parameterHandler变量

代码备注:也许上面的代码,你没有看懂,但是没有关系,其中的细节你可以不去探究,你只要明白代码的字面意思,createParameterHandler(),这是创建ParameterHandler对象,Plugin.wrap就是包装,把两个类包装一下,重新生成一个新的类。你只要能理清“原身->变身”这个过程,这就足够了,就能把MyBatis插件机制的精髓已经掌握了。

4、MyBatis拦截器插件整个运行过程

4.1、没有插件的运行过程

mybatis-no-plugins.png

4.2、有插件的运行过程

mybatis-have-plugins.png

5、本文小结

大凡提到“MyBatis插件”,很多人感觉这是一个高大上的玩意,深入MyBatis源码内核,威力巨大,也破坏巨大,让人万分小心,惴惴不安。其实不然,添加插件,就是给mybatis核心对象生成了变身而已。也就是说,一旦配置上插件,ParameterHandler,ResultSetHandler,StatementHandler,Executor这四大核心对象,将会生成变身,是一种代理对象,而不再是原身,仅此而已。通过本文的一针见血,希望大家能够放开手脚,大胆尝试,开发MyBatis插件不是困难的事情。当然,更多的插件开发细节介绍,敬请关注 mybatis插件 这个系列。

添加新评论