MyBatis Interceptor

MyBatis的拦截器可以用于在以下对象及方法中拦截修改:

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

每一个方法会对应不同的参数列表, 这些需要体现在Intercepts的Signature中

配置

除了实现Interceptor接口以外, 需要在项目中做以下配置

application.yml

增加对应的mybatis-config.xml, 因为现在还不支持在yml中配置plugin

mybatis:
  type-aliases-package: com.compayn.proj.commons.api.dto
  mapper-locations: classpath:mapper/*.xml
  config-location: classpath:mybatis-config.xml

mybatis-config.xml

增加mybatis配置文件, 注意这里配置的拦截器, 其实际执行顺序是自下而上的

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <settings>
        <setting name="..." value="true" />
    </settings>

    <plugins>
        <!-- The invocation order is bottom up -->
        <plugin interceptor="com.company.proj.commons.impl.interceptor.BaseInterceptor" />
    </plugins>

</configuration>

  

Interceptor实现

一个简单的拦截器实现, 可以输出执行的sql, 以及执行时间.

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Statement;
import java.util.Properties;

@Intercepts({
        @Signature(type = StatementHandler.class, method = "batch", args = { Statement.class}),
        @Signature(type = StatementHandler.class, method = "update", args = { Statement.class}),
        @Signature(type = StatementHandler.class, method = "query", args = { Statement.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class,Object.class})})
public class BaseInterceptor implements Interceptor {
    private static Logger logger = LoggerFactory.getLogger(BaseInterceptor.class);

    /**
     * 用于封装目标对象, 可以返回目标对象本身也可以返回一个它的代理, 这将决定是否会进行拦截
     */
    @Override
    public Object plugin(Object target) {
        if (target instanceof Executor) { // 仅当对象为Executor时, 才使用本插件
            return Plugin.wrap(target, this);
        } else {
            return target;
        }
    }

    /**
     * 用于配置本插件的相关属性
     */
    @Override
    public void setProperties(Properties properties) {
        // Do nothing
    }

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        long start = System.currentTimeMillis();

        Object target = invocation.getTarget(); //被代理对象

        if (target instanceof Executor) {
            MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
            Object parameter = invocation.getArgs()[1];
            BoundSql boundSql = mappedStatement.getBoundSql(parameter);
            String sql = boundSql.getSql();
            logger.info("SQL: {}", sql);
        }

        Object result = invocation.proceed();
        long duration = System.currentTimeMillis() - start;
        logger.info("Time elapsed: {}ms", duration);
        return result;
    }
}

代码说明

@Intercepts 注解: 这个地方配置需要拦截的对象方法, 每个方法对应一个Signature, 这个Signature由对象类型, 方法名和参数组成, 方法名和参数可以直接参考这个对象的接口.

Object plugin(Object target)接口: 用于封装目标对象, 可以返回目标对象本身也可以返回一个它的代理, 这将决定是否会进行拦截

void setProperties(Properties properties)接口: 用于配置本插件的相关属性, 值可以通过Mybatis配置文件传入

Object intercept(Invocation invocation) throws Throwable接口: 执行拦截的方法, 其中 invocation.getTarget() 可以看到实际被代理的对象, 根据对象类型不同, 可以读取这个对象方法的参数并进行需要的操作.

 

posted on 2020-04-21 18:06  Milton  阅读(2455)  评论(0编辑  收藏  举报

导航