MyBatis 插件(plugins)介绍
本文修改日期:2019年10月10日
1、MyBatis插件
MyBatis允许用户在已映射语句执行过程中的某一点进行拦截调用。MyBatis使用插件来拦截的方法调用,故此MyBatis插件通常称为:Mybatis拦截器。默认情况下,MyBatis允许使用插件来拦截的对象包括下面的四大金刚:
- Executor
- ParameterHandler
- ResultSetHandler
- StatementHandler
说明:Mybatis可以对这四个接口中所有的方法进行拦截。
Mybatis拦截器只能拦截四种类型的接口:Executor、StatementHandler、ParameterHandler和ResultSetHandler。这是在Mybatis的Configuration中写死了的。就是在下面的几个函数里面生成代理对象实现拦截的:
这四个类中方法的细节可以通过查看每个方法的签名来发现,或者直接查看 MyBatis 发行包中的源代码。如果你想做的不仅仅是监控方法的调用,那么你最好相当了解要重写的方法的行为。因为如果在试图修改或重写已有方法的行为的时候,你很可能在破坏 MyBatis 的核心模块。这些都是更低层的类和方法,所以使用插件的时候要特别当心。
1.1、MyBatis插件(代理类)示例图
如上图所示:MyBatis系统最终会将插件包装成代理类,通过代理类来执行插件里面的功能。
2、MyBatis自定义插件的实现
通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可。
Interceptor 接口的定义如下所示:
public interface Interceptor {
//拦截器具体实现
Object intercept(Invocation invocation) throws Throwable;
//拦截器的代理类
Object plugin(Object target);
//添加属性
void setProperties(Properties properties);
}
对于实现自己的Interceptor而言,有两个很重要的注解:
(1)@Intercepts用于表明当前的对象是一个Interceptor。其值是一个@Signature数组。代码如下所示:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Intercepts
{
Signature[] value();
}
(2)@Signature则表明要拦截的接口、方法以及对应的参数类型。代码如下所示:
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Signature {
Class<?> type();
String method();
Class<?>[] args();
}
下面来看一个自定义的简单Interceptor,出自MyBatis官方教程:
// ExamplePlugin.java
@Intercepts({@Signature(
type= Executor.class,
method = "update",
args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {
private Properties properties = new Properties();
public Object intercept(Invocation invocation) throws Throwable {
// implement pre processing if need
Object returnObject = invocation.proceed();
// implement post processing if need
return returnObject;
}
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}
代码分析:
在上面的源码中Plugin.wrap(),是当前拦截器(ExamplePlugin)的代理类。MyBatis通过这个代理类来实现拦截的功能。从这里也可以看出来,MyBatis插件和拦截器的关系:插件是拦截器的代理类。
<!-- mybatis-config.xml -->
<plugins>
<plugin interceptor="org.mybatis.example.ExamplePlugin">
<property name="someProperty" value="100"/>
</plugin>
</plugins>
Mybatis在注册自定义的拦截器时,会先把对应拦截器下面的所有property通过Interceptor的setProperties方法注入给对应的拦截器。然后这个插件将会拦截在 Executor 实例中所有的 “update” 方法调用,这里的 Executor 是负责执行低层映射语句的内部对象。