My Batis 允许在己映射语句执行过程中的某一点进行拦截调用。默认情况下, MyBatis 允许 使用插件来拦截的接口和方法包括以下几个。
• Executor ( update 、 query 、 flushStatements 、 commit 、 rollback 、 get Transaction、 close、 isClosed)
• ParameterHandler ( getParameterObj ect、 setParameters)
• ResultSetHandler ( handleResul tSets 、 handleCursorResultSets 、 handleOutputParameters)
• StatementHandler (prepare、 parameterize、 batch、 update、 query)
拦截器接口
MyBatis插件可以用来实现拦截器接口,在实现类中对拦截对象和方法进行处理
Interceptor 接口代码
public interface Interceptor {
Object intercept(Invocation invocation) throws Throwable;
Object plugin(Object target) ;
void setProperties(Properties properties);
}
mybatis-config.xml
<plugins>
<plugin interceptor="tk.mybatis.simple.plugin.XXXInterceptor>
<property name="prop1" value="value1"/>
<property name="prop2" value="value2"/>
<plugin/>
</plugins>
在配置拦截器时, plugin 的 interceptor 属性为拦截器实现类的全限定名称,如果需 要参数,可以在 plugin 标签内通过 property 标签进行配置,配置后的参数在拦截器初始化 时会通过 setProperties 方法传递给拦截器。在拦截器中可以很方便地通过 Properties 取得配置的参数值。
plugin方法。这个方法的参数 target 就是拦截器要拦截的对象,该方法会 在创建被拦截的接口实现类时被调用。该方法的实现很简单 ,只需要调用 MyBatis 提供的 Plugin (org . apache. ibatis. plug in. Plugin )类的 wrap 静态方法就可以通过 Java 的 动态代理拦截目标对象。这个接口方法通常的实现代码如下。
@Override public Object plugin(Object target) {
return Plugin .wrap(target , this) ;
}
intercept 方法是 MyBatis 运行时要执行的拦截方法。通过该方法的参数 invocation 可以得到很多有用的信息,该参数的常用方法如下。
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object target =invocation.getTarget ();
Method method= invocation.getMethod() ;
Object[] args = invocation.getArgs() ;
Object result =invocation .proceed ();
return result;
}
getTarget();方法可以获取当前被拦截的对象
getMethod();可以获取当前被拦截 的方法
getArgs();方法可以返回被拦截方法中的参数
proceed(); 可以执行被拦截对象真正的方法
拦截器签名
@Intercepts(org . apache . ibatis . plugin . Intercepts )和签名注解@Signature Corg . apache . ibatis . plugin . Signature ),这两个注解用来配置拦截器要拦截的接口 的方法。@ Intercepts 注解中的属性是一个@Signature (签名)数组,可以在同一个拦截器中 同时拦截不同的接口和方法
@Intercepts({
@Signature (
type = ResultSetHandler.class,
method = ” handleResultSets”,
args = {Statement . class})
})
public class ResultSetinterceptor implements Interceptor
@Signature 注解包含以下三个属性。
type: 设置拦截的接口,可选值是前面提到的4 个接口 。
method: 设置拦截接口中的方法名, 可选值是前面提到的4 个接口对应的方法,需要和接口匹配。
args: 设置拦截方法的参数类型数组, 通过方法名和参数类型可以确定唯一一个方法。
通过不同的注解来配置可以拦截的方法,在方法完成后调用配置该注解的类.由于 MyBatis 代码具体实现的原因,可以被拦截的 4 个接口中的方法并不是都可以被拦截的,下面将针对这 4 种接口,将可以被拦截的方法以及方法被调用的位置和对应的拦截器签名 依次列举出来,大家可以根据方法调用的位置和方法提供的参数来选择想要拦截的方法
Executor 接口
· int update(MappedStatement var1, Object var2) throws SQLException;
该方法会在所有的 INSERT、 UPDATE、 DELETE 执行时被调用,因此如果想要拦截这3类操作,可以拦截该方法。接口方法对
应的签名如下
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class,Object.class})
· <E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4) throws SQLException;
该方法会在所有 SELECT 查询方法执行时被调用。过这个接口参数可以获取很多有用的信息,因此这是最常被拦截的一个方法。使用该
方法需要注意的是,虽然接口中还有一个参数 更多的同名接口 ,但由于 MyBatis 的设计原因,这个参数多的接口不能被拦截。接口方法对
应的签名如下
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class,Object.class,RowBounds.class, ResultHandler.class})
· <E> Cursor<E> queryCursor(MappedStatement var1, Object var2, RowBounds var3) throws SQLException;
该方法只有在查询的返回值类型为Cursor 时被调用 。接口方法对应的签名如下
@Signature(type = Executor.class, method = "queryCursor", args = {MappedStatement.class,Object.class,RowBounds.class})
· List<BatchResult> flushStatements() throws SQLException;
该方法只在通过SqlSession方法调用flushStatements方法或执行的接口方法中带 有@Flush注解时才被调用 ,接口方法对应的签名如下。
@Signature(type = Executor.class, method = "flushStatements", args = {})
· void commit(boolean var1) throws SQLException;
该方法只在通过SqlSession方法调用commit方法时才被调用,接口方法对应的签名如下。
@Signature(type = Executor.class, method = "commit", args = {boolean.class})
· void rollback(boolean var1) throws SQLException;
该方法只在通过SqlSession方法调用rollback方法时才被调用,接口方法对应的签名如下。
@Signature(type = Executor.class, method = "rollback", args = {boolean.class})
· Transaction getTransaction();
该方法只在通过 SqlSession方法获取数据库连接时才被调用,接口方法对应的签名如下。
@Signature(type = Executor.class, method = "getTransaction", args = {})
· void close(boolean var1);
该方法只在延迟加载获取新 Executor后才会被执行,接口方法对应的签名如下。
@Signature(type = Executor.class, method = "close", args = {boolean.class})
· boolean isClosed();
该方法只在延迟加载执行查询方法前被执行,接口方法对应的签名如下。
@Signature(type = Executor.class, method = "isClosed", args = {})
ParameterHandler 接口
· Object getParameterObject();
该方法只在执行存储过程处理出参的时候被调用。接口方法对应的签名如下。
@Signature(type = ParameterHandler.class, method = "getParameterObject", args = {})
· void setParameters(PreparedStatement var1) throws SQLException;
该方法在所有数据库方法设置 SQL 参数时被调用。接口方法对应的签名如下。
@Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class})
ResultSetHandler接口
· <E> List<E> handleResultSets(Statement var1) throws SQLException;
该方法会在除存储过程及返回值类型为 Cursor<T> ( org.apache.ibatis.cursor.Cursor<T>)以外的查询方法中被调用。接口方法对应的签名如下。
@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
· <E> Cursor<E> handleCursorResultSets(Statement var1) throws SQLException;
只会在返回值类型为 Cursor<T>的查询方法中被调用 , 接口方法对应的签名如下。
@Signature(type = ResultSetHandler.class, method = "handleCursorResultSets", args = {Statement.class})
· void handleOutputParameters(CallableStatement var1) throws SQLException;
该方法只在使用存储过程处理出参时被调用 ,接口方法对应的签名如下。
@Signature(type = ResultSetHandler.class, method = "handleOutputParameters", args = {Statement.class})
ResultSetHandler 接口的第一个方法对于拦截处理 MyBatis 的查询结果非常有用,并 且由于这个接口被调用的位置在处理二级缓存之前,因此通过这种方式处理的结果可以执行二 级缓存。
StatementHandler接口
· Statement prepare(Connection var1, Integer var2) throws SQLException;
该方法会在数据库执行前被调用 , 优先于当前接口中的其他方法而被执行。 接口方法对应 的签名如下。
@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
· void parameterize(Statement var1) throws SQLException;
该方法在 prepare 方法之后执行,用于处理参数信息, 接口方法对应的签名如下。
@Signature(type = StatementHandler.class, method = "parameterize", args = {Statement.class})
· void batch(Statement var1) throws SQLException;
在全局设置配置 defaultExecutorType=”BATCH”时,执行数据操作才会调用该方法, 接口方法对应的签名如下。
@Signature(type = StatementHandler.class, method = "batch", args = {Statement.class})
· <E> List<E> query(Statement var1, ResultHandler var2) throws SQLException;
执行 SELECT 方法时调用,接口方法对应的签名如下。
@Signature(type = StatementHandler.class, method = "query", args = {Statement.class,ResultHandler.class})
· <E> Cursor<E> queryCursor(Statement var1) throws SQLException;
只会在返回值类型为 Cursor<T>的查询中被调用 , 接口 方法对应的签名如下。
@Signature(type = StatementHandler.class, method = "queryCursor", args = {Connection.class, Integer.class})