资讯专栏INFORMATION COLUMN

【深入浅出MyBatis笔记】插件

leon / 553人阅读

摘要:插件插件接口在中使用插件,我们必须实现接口。它将直接覆盖你所拦截对象原有的方法,因此它是插件的核心方法。插件在对象中的保存插件的代理和反射设计插件用的是责任链模式,的责任链是由去定义的。

插件 1、插件接口

在MyBatis中使用插件,我们必须实现接口Interceptor。

public interface Interceptor {
  // 它将直接覆盖你所拦截对象原有的方法,因此它是插件的核心方法。
  // Intercept里面有个参数Invocation对象,通过它可以反射调度原来对象的方法
  Object intercept(Invocation invocation) throws Throwable;

  // 作用是给被拦截对象生成一个代理对象,并返回它。target是被拦截对象
  Object plugin(Object target);

  // 允许在plugin元素中配置所需参数,方法在插件初始化的时候就被调用了一次
  void setProperties(Properties properties);

}
2、插件初始化

插件的初始化是在MyBatis初始化的时候完成的。

public class XMLConfigBuilder extends BaseBuilder {
  ......
  private void pluginElement(XNode parent) throws Exception {
    if (parent != null) {
      for (XNode child : parent.getChildren()) {
        String interceptor = child.getStringAttribute("interceptor");
        Properties properties = child.getChildrenAsProperties();
        Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
        interceptorInstance.setProperties(properties);
        configuration.addInterceptor(interceptorInstance);
      }
    }
  }
}

在解析配置文件的时候,在MyBatis的上下文初始化过程中,就开始读入插件节点和我们配置的参数,同时使用反射技术生成对应的插件实例,然后调用插件方法中的setProperties方法,设置我们配置的参数,然后将插件实例保存到配置对象中,以便读取和使用它。

插件在Configuration对象中的保存:

  public void addInterceptor(Interceptor interceptor) {
    interceptorChain.addInterceptor(interceptor);
  }
3、插件的代理和反射设计

插件用的是责任链模式,MyBatis的责任链是由interceptorChain去定义的。在MyBatis创建Executor执行器的时候,我们可以看到有如下的一段代码:

executor = (Executor) interceptorChain.pluginAll(executor);

再看下Interceptor的pluginAll方法:

public class InterceptorChain {
  private final List interceptors = new ArrayList();

  public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      // plugin方法是生成代理对象的方法
      // 可以看出来,如果有多个插件的话,会生成多层代理的代理对象
      target = interceptor.plugin(target);
    }
    return target;
  }
  ......
}

MyBatis为我们提供了Plugin类用于生成代理对象。

public class Plugin implements InvocationHandler {
  ......

  public static Object wrap(Object target, Interceptor interceptor) {
    Map, Set> signatureMap = getSignatureMap(interceptor);
    Class type = target.getClass();
    Class[] interfaces = getAllInterfaces(type, signatureMap);
    if (interfaces.length > 0) {
      return Proxy.newProxyInstance(
          type.getClassLoader(),
          interfaces,
          new Plugin(target, interceptor, signatureMap));
    }
    return target;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      Set methods = signatureMap.get(method.getDeclaringClass());
      // 如果存在签名的拦截方法,插件的intercept方法将被调用
      if (methods != null && methods.contains(method)) {
        return interceptor.intercept(new Invocation(target, method, args));
      }
      // 否则,直接反射调度我们要执行的方法
      return method.invoke(target, args);
    } catch (Exception e) {
      throw ExceptionUtil.unwrapThrowable(e);
    }
  }
}

在调用插件的拦截方法时,可以看到传递了一个新创建的Invocation对象。

interceptor.intercept(new Invocation(target, method, args));

Invocation类封装了被代理的对象、方法及其参数。

public class Invocation {
  public Invocation(Object target, Method method, Object[] args) {
    this.target = target;
    this.method = method;
    this.args = args;
  }

  // 这个方法会调度被代理对象的真实方法, 所以我们通过这个方法直接调用被代理对象原来的方法
  // 如果多个插件的话,我们知道会生成多层代理对象,那么每层被代理都可以通过Invocation调用这个proceed方法,
  // 所以在多个插件的环境下,调度proceed()方法时,MyBatis总是从最后一个代理对象运行到第一个代理对象,
  // 最后是真实被拦截的对象方法被运行
  public Object proceed() throws InvocationTargetException, IllegalAccessException {
    return method.invoke(target, args);
  }
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/69549.html

相关文章

  • 深入浅出MyBatis笔记MyBatis的解析和运行原理

    摘要:的解析和运行原理构建过程提供创建的核心接口。在构造器初始化时会根据和的方法解析为命令。数据库会话器定义了一个对象的适配器,它是一个接口对象,构造器根据配置来适配对应的对象。它的作用是给实现类对象的使用提供一个统一简易的使用适配器。 MyBatis的解析和运行原理 构建SqlSessionFactory过程 SqlSessionFactory提供创建MyBatis的核心接口SqlSess...

    bitkylin 评论0 收藏0
  • Mybatis学习笔记

    摘要:学习笔记有官方的中文开发文档并且针对使用者比较友好是一款优秀的持久层框架,它支持定制化存储过程以及高级映射。它只和配置有关,存在的意义仅在于用来减少类完全限定名的冗余,为了简化中的书写。 Mybatis学习笔记 mybatis有官方的中文开发文档并且针对使用者比较友好:http://www.mybatis.org/mybatis-3/zh/ MyBatis 是一款优秀的持久层框架,它支...

    jsyzchen 评论0 收藏0
  • Java深入-框架技巧

    摘要:从使用到原理学习线程池关于线程池的使用,及原理分析分析角度新颖面向切面编程的基本用法基于注解的实现在软件开发中,分散于应用中多出的功能被称为横切关注点如事务安全缓存等。 Java 程序媛手把手教你设计模式中的撩妹神技 -- 上篇 遇一人白首,择一城终老,是多么美好的人生境界,她和他历经风雨慢慢变老,回首走过的点点滴滴,依然清楚的记得当初爱情萌芽的模样…… Java 进阶面试问题列表 -...

    chengtao1633 评论0 收藏0
  • Java 实战开发之mybatis三剑客(五)

    摘要:插件功能非常强大,,方法跳转提示,分页插件。三地址使用该插件在引入该插件具体使用,我们在以后的中再学习具体的方法。更多请参考学习笔记一入门 mybatis 插件功能非常强大,mybatis-generator,mybatis-plugin方法跳转提示,mybatis-pagehelper分页插件。 一、mybatis-generator 1、mybatis-generator配置 先在...

    NusterCache 评论0 收藏0

发表评论

0条评论

leon

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<