mybatis插件原理
mybatis的插件实现主要是基于JDK动态代理来实现的。下面来根据源码执行流程来分析代理执行的逻辑
大致分为如下几个流程:
插件定义和配置
可以通过xml的方式或者JavConfig两种方式定义插件,例如:
在 MyBatis 配置 xml 中配置拦截器插件
<plugins>
<!-- com.github.pagehelper为PageHelper类所在包名 -->
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- 使用下面的方式配置参数,后面会有所有的参数介绍 -->
<property name="param1" value="value1"/>
</plugin>
</plugins>
在 Spring 配置文件中配置拦截器插件
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注意其他配置 -->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<!--使用下面的方式配置参数,一行配置一个 -->
<value>
params=value1
</value>
</property>
</bean>
</array>
</property>
</bean>
插件加载
插件的配置信息是封装在Configuration对象中,这个对象的封装完成在SqlSessionFactoryBean的afterPropertiesSet方法中,熟悉spring生命周期的同学应该对这个方法比较熟悉,该方法会在bean实例化的时候会被调用。
具体来讲就是在buildSqlSessionFactory方法中,插件载入后就存放在Configuration中。
protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
.....
if (!isEmpty(this.plugins)) {
Stream.of(this.plugins).forEach(plugin -> {
targetConfiguration.addInterceptor(plugin);
LOGGER.debug(() -> "Registered plugin: '" + plugin + "'");
});
}
......
}
生成代理对象
mybatis支持对四个重要对象进行插件扩展,分别是:
ParameterHandler
ResultSetHandler
StatementHandler
Executor
每个对象的绑定时机不尽一致。其中Executor 的绑定发生在客户端open一个session的时候,详细的执行调时序图如下见下图
Plugin中生成的代理对象。
插件调用和执行
当我们使用执行器执行数据库操作的时候,实际上会执行上面生成的代理对象invoke方法中的interceptor.intercept命令,也就是会执行我们自定义的Interceptor中的intercept()方法,在这里面我们可以做一些SQL组装、监控之类的事情;