mybatis plugins_[Mybatis]-[基础支持层]-插件-plugin标签解析

94c600cad6f94dd0b8b40e3e0a6a5a5b.png
该系列文章针对 Mybatis 3.5.1 版本

一、Mybatis 插件的作用

Mybatis 针对 SQL 映射语句执行过程中进行拦截处理,而对应的拦截器 Mybaits 又称之为 插件(这些插件就是Mybatis的扩展点)

在 Mybaits 中允许用插件来拦截的方法包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

通过插件的方式可以实现 SQL打印、分页等插件功能实现。

二、Mybatis 插件配置

插件代码逻辑实现后还需要加载到 Mybatis 中才能生效,Mybatis 提供了 <plugin> 配置标签,用来声明。

插件在 mybatis-config.xml 中的配置案例,如下:

ba42be3e158a0d6bb87d0b675bfceceb.png

通过 <plugin> 标签,然后在指定的属性 <plugin interceptor=class全路径> interceptor 配置插件实现类的全路径即可。

三、`<plugins>` 标签解析

再来回顾一下,XMLConfigBuilder解析时序简图,如下:

a1238b7de22c404a774627c41410f5e0.png

在时序图中<plugins>加载解析在XMLConfigBuilder#pluginElement中完成,相关解析代码如下:

7f2720507d4aca3ff3becd0153dfea58.png

如上述代码,<plugins> 的解析流程很简单

1、加载 <plugins> 下的子标签 <plugin>
2、获取 <plugin interceptor=class全路径名> 中 interceptor 属性中的 class 全路径名
3、class 必须实现了 Interceptor接口,如果满足,通过反射实例化类
4、把类加载到存放拦截器的拦截器容器,拦截器链 InterceptorChain

简单来看一下 InterceptorChain 代码定义

5a424de9e84db8607f00ff6cc491b329.png

如上述代码所示,InterceptorChain 本身就是一个容器,用来存放所有从 <plugins> 读取到的拦截器对象。

而这里的拦截器列表,在使用过程中,会通过代理的方式,对目标对象层层代理,通过责任链的方式实现代码执行前后的层层过滤,相关逻辑图如下:

570ece2b921e87d65e3ec1ba700c09b4.png

四、interceptor 过滤链代理处理代码

上面提到了 interceptor 过滤链的实现是通过代理的方式层层包裹实现的,下面来简单阅读代理流程源码

Mybatis 中只针对 ExecutorParameterHandlerResultSetHandlerStatementHandler,这四种情况追加了过滤连的处理。

相关的处理方法入口为 InterceptorChain#pluginAll,如下图

663bcd86f08e6a6af31e5dff8a892c5d.png

如上述代码,遍历所有的插件,调用插件本身的plugin方法来处理,也就是Interceptor#plugin,来看通用实现

(也可以自定义实现逻辑),代码如下

1bc63550f68ad55dce5aa35b2ef21462.png

如上述代码,通用的代理逻辑交由工具类 Plugin 来实现,

接着来看一下 Plugin#wrap 方法源码

112c3fa975610420e0bab71cd8dc9c80.png

如上述源码所示,通过配对当前 interceptor 是否符合目标对象 target ,如果配对,构建相应的代理对象。

以此类推,随后实现如下图的效果:

570ece2b921e87d65e3ec1ba700c09b4.png

五、总结

通过上述源码解析能够知道一个插件,也就是一个 Interceptor 的定义需要满足两个条件

1、该插件实现类实现了 Interceptor 接口
2、该插件实现类通过注解 @Intercepts 指定了该插件需要拦截的对象,也就是ExecutorParameterHandlerResultSetHandlerStatementHandler 中的一种或者多种

<plugins> 标签中配置的是一系列拦截器,这些拦截器通过代理的方式组合起来实现了过滤器链。

而这些过滤器数据存储在 InterceptorChain中,最终数据仍然会存在 Configuration 中,
相关的 Configuration 逻辑图如下:

18f189744a959ce075ee6573e6bd715d.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值