Mybatis 插件开发与 Spring Boot 整合

269 阅读2分钟

Mybatis 插件开发

MyBatis 允许你在映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

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

这些类中方法的细节可以通过查看每个方法的签名来发现,或者直接查看 MyBatis 发行包中的源代码。 如果你想做的不仅仅是监控方法的调用,那么你最好相当了解要重写的方法的行为。 因为在试图修改或重写已有方法的行为时,很可能会破坏 MyBatis 的核心模块。 这些都是更底层的类和方法,所以使用插件的时候要特别当心。

通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可。

update 等括号里面的内容代表的是当前类型的可拦截方法。

至于拦截参数在官方文档中未标注出来,得去看源码位置,具体可参数插件执行位置 org.apache.ibatis.session.Configuration 的每个类型的方式。

这里我把所有拦截方法的参数列举出来。

Executor

  • update(MappedStatement ms, Object parameter)
  • query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
  • flushStatements(boolean isRollBack)
  • commit(boolean required)
  • rollback(boolean required)
  • getTransaction()
  • close(boolean forceRollback)
  • isClosed()

ParameterHandler

  • getParameterObject()
  • setParameters(PreparedStatement ps)

ResultSetHandler

  • handleResultSets(Statement stmt)
  • handleOutputParameters(CallableStatement cs)

StatementHandler

  • prepare(Connection connection, Integer transactionTimeout)
  • parameterize(Statement statement)
  • batch(Statement statement)
  • update(Statement statement)
  • query(Statement statement, ResultHandler resultHandler)

知道这些之后,下面我们进行写一个插件的示例。

定义 Mybatis 插件

自定义插件

@Intercepts({@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class TestInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        RowBounds arg = (RowBounds) args[2];
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        if (target instanceof Executor){
            return Plugin.wrap(target,this);
        }
        return target;
    }

    @Override
    public void setProperties(Properties properties) {}
}

type 的值是 Executor 的这 4 个值。method 是对应的可拦截方法,args 参数是我列举出来的可以拦截的参数。

intercept 方法中通过 invocation.getArgs() 可以获取上面 args 配置的拦截参数,位置和配置的一致。最后一定要 invocation.proceed() 调用目标方法。

plugin 方法返回插件对象,其中只对相应类型的实例返回代理对象,其他则返回源对象。

将插件添加到 Mybatis 中

@Component
public class TestStartLoadBean implements SmartInitializingSingleton {

    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    @Override
    public void afterSingletonsInstantiated() {
        sqlSessionFactory.getConfiguration().addInterceptor(new TestInterceptor());
    }
}

等 Spring 启动完成后注入 SqlSessionFactory,然后将插件添加进去。

想要更加高级的开发请参考分页插件 com.github.pagehelper.PageHelper 和 Mybatis plus 的 com.baomidou.mybatisplus.extension.plugins.SqlExplainInterceptor 等。