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() 可以看到实际被代理的对象, 根据对象类型不同, 可以读取这个对象方法的参数并进行需要的操作.
来源:oschina
链接:https://my.oschina.net/u/4282636/blog/3302301