插件使用
- xml配置
<plugins>
<plugin interceptor="cn.zhutan.mybatistest.plugin.MyPlugin">
<!--自定义属性-->
<!--<property name="key1" value="value1"/>-->
</plugin>
</plugins>
- 自定义插件类
// 注解作用, 指定拦截的具体某个方法: 类, 方法名, 方法参数确定方法的唯一性
@Intercepts(@Signature(type = Executor.class, method = "query",
args = {
MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))
public class MyPlugin implements Interceptor {
// 这个方法会在指定的拦截方法时调用
@Override
public Object intercept(Invocation invocation) throws Throwable {
// invocation对象保存着method调用的条件
// invocation.proceed()实际上就是method.invoke调用实际方法
// 由于拦截到具体某个方法后, mybatis不知道什么时候要处理实际的逻辑, 于是就把实际调用method.invoke转成Invocation对象中的proceed方法
Object proceed = invocation.proceed();
System.out.println("proceed:" + proceed);
return proceed;
}
/**
* 注意: 这个plugin方法会在创建以下4个对象时均会调用, target为对应的对象
* Executor, ParameterHandler, ResultSetHandler, StatementHandler
*
* @param target 有可能是目标对象, 也有可能是上次代理后的对象, 取决于上一个拦截器的处理
* @return 返回target对象或者代理后的对象
*/
@Override
public Object plugin(Object target) {
// 返回原对象或者被代理后的对象, 取决于当前是否是定义的拦截接口
// 比如定义的拦截接口是Executor, 那么这里在创建Executor后, 会代理Executor, 而其他接口ParameterHandler创建后, 就返回实际对象, 并不会代理
Object wrap = Plugin.wrap(target, this);
System.out.println("target:" + target.getClass() + ", warp: " + wrap.getClass());
return wrap;
}
// 这个方法在解析插件标签后, 添加到拦截器集合之前会调用
@Override
public void setProperties(Properties properties) {
System.out.println(properties);
}
}
读取解析xml插件标签plugin
插件接口
public interface Interceptor {
Object intercept(Invocation invocation) throws Throwable;
default Object plugin(Object target) {
return Plugin.wrap(target, this);
}
default void setProperties(Properties properties) {
// NOP
}
}
查看XMLConfigBuilder的parseConfiguration方法
private void parseConfiguration(XNode root) {
try {
// issue #117 read properties first
// 解析<properties>标签: 将指定文件的properties解析为键值对放到variables中, 后续标签解析会解析占位符${xxx}, 进行替换
propertiesElement(root.evalNode("properties"));
// 解析<settings>标签, name=value形式装在Properties并返回
Properties settings = settingsAsProperties(root.evalNode("settings"));
// 加载setting配置vfsImpl到configuration, 值以逗号隔开, 但是当前使用的是逗号后面最后一个
loadCustomVfs(settings);
// 加载setting配置logImpl到configuration
loadCustomLogImpl(settings);
// 解析<typeAliases>标签, 往别名typeAliases的map中注册添加
typeAliasesElement(root.evalNode