mybatis插件拦截器使用及原理

插件使用

  1. xml配置
<plugins>
   <plugin interceptor="cn.zhutan.mybatistest.plugin.MyPlugin">
      <!--自定义属性-->
      <!--<property name="key1" value="value1"/>-->
   </plugin>
</plugins>
  1. 自定义插件类
// 注解作用, 指定拦截的具体某个方法: 类, 方法名, 方法参数确定方法的唯一性
@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
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值