拦截器接口介绍
MyBatis 插件可以用来实现拦截器接口 Interceptor(org.apache.ibatis.plugin.Interceptor),在实现类中对拦截对象和方法进行处理。
先来看拦截器接口,了解该接口的每一个方法的作用和用法。Interceptor 接口代码如下。
public interface Interceptor {
Object intercept(Invocation var1) throws Throwable;
Object plugin(Object var1);
void setProperties(Properties var1);
}
先从最简单的拦截器接口讲起。首先是 setProperties 方法,这个方法用来传递插件的参数,可以通过参数来改变插件的行为。参数值是如何传递进来的呢?要搞清楚这个问题,需要先看一下拦截器的配置方法。在 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.plugin.Plugin) 类的 wrap 静态方法就可以通过 Java 的动态代理拦截目标对象。这个接口方法通常的实现代码如下。
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
Plugin.wrap 方法会自动判断拦截器的签名和被拦截对象的接口是否匹配,只有匹配的情况下才会使用动态代理拦截目标对象,因此在上面的实现方法中不必做额外的逻辑判断。
最后一个 intercept 方法是 MyBatis 运行时要执行的拦截方法。通过该方法的参数 invocation 可以得到很多有用的信息,该参数的常用方法如下。
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() 方法可以返回被拦截方法中的参数。通过调用 invocation.proceed();可以执行被拦截对象真正的方法,proceed() 方法实际上执行了 method.invoke(target,args) 方法,上面的代码中没有做任何特殊处理,直接返回了执行的结果。
当配置多个拦截器时,MyBatis 会遍历所有拦截器,按顺序执行拦截器的 plugin 方法,被拦截的对象就会被层层代理。在执行拦截对象的方法时,会一层层地调用拦截器,拦截器通过 invocation.proceed() 调用下一层的方法,直到真正的方法被执行。方法执行的结果会从最里面开始向外一层层返回,所以如果存在按顺序配置的 A、B、C 三个签名相同的拦截器,MyBaits 会按照 C>B>A>target.proceed()>A>B>C 的顺序执行。如果 A、B、C 签名不同,就会按照 MyBatis 拦截对象的逻辑执行。