本文采用知识共享 署名-相同方式共享 4.0 国际 许可协议进行许可。
访问 https://creativecommons.org/licenses/by-sa/4.0/ 查看该许可协议。

MyBatis 的插件基于拦截器思想,基于动态代理实现,我们可以对 MyBatis 中以下四大组件中的 method 进行拦截

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

我们可以通过实现 Interceptor 接口,实现和重写接口中的三个扩展方法:

  1. intercept(Invocation invocation):此接口为主扩展方法,invocation.proceed() 可以继续运行被拦截的方法,使我们可以在前后扩展。
  2. Object plugin(Object target):是的它就是上一节我们分析原理时执行的 plugin 函数,此函数是一个默认方法,可以重写它对创建代理时扩展。
  3. setProperties(Properties properties):在 SqlMapConfig.xml 中声明插件的 plugin 标签定义的参数,会传递到 properties 中。
3.1.7.2) 栗子:

定义:

@Intercepts({@Signature(
        type = Executor.class, method = "update",
        args = {MappedStatement.class, Object.class}
)})
public class ExampleInterceptor implements Interceptor {

  @Override
  public Object intercept(Invocation invocation) throws Throwable {
    /* Before process */ Object result = invocation.proceed(); /* After process */
    return result;
  }
}

声明:

<plugins>
  <plugin interceptor="cat.wars.ExampleInterceptor"></plugin>
</plugins>
3.1.7.3) 原理:

Configuration 中创建四大组件时都会调用 interceptorChain.pluginAll 方法来扩展,如 ParameterHandler
,从而返回一个重重代理对象

Configuratoin

  public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
    // Create instance
    ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);
    // 将创建的 instance 交给 Interceptor Chain,执行完 pluginAll 后会返回一个重重(loop)代理对象
    parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);
    return parameterHandler; // 返回代理对象
  }

InterceptorChain

public Object pluginAll(Object target) {
  for (Interceptor interceptor : interceptors) {
    target = interceptor.plugin(target); // 执行定义的 plugin 实现动态代理
  }
  return target;
}