Mybatis源码解读-插件

// XMLConfigBuilder#pluginElement(XNode parent)
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).getDeclaredConstructor().newInstance();
      interceptorInstance.setProperties(properties);
      // 将插件添加到配置的插件链中,等待后续使用
      configuration.addInterceptor(interceptorInstance);
    }
  }
}

configuration.addInterceptor做得操作很简单
* 包装 上面讲了插件的注册,最后调用的是configuration.addInterceptor,最终调用的是InterceptorChain#addInterceptor

public class InterceptorChain {

  private final List interceptors = new ArrayList<>();
  /*
   * 每当四大对象创建时,都会执行此方法
   * 满足拦截条件,则返回Plugin代理,否则返回原对象
   * @param target Mybatis四大对象之一
   */
  public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      // 调用每个插件的plugin方法,判断是否需要代理
      target = interceptor.plugin(target);
    }
    return target;
  }
  // 将拦截器添加interceptors集合中存起来
  public void addInterceptor(Interceptor interceptor) {
    interceptors.add(interceptor);
  }

  public List getInterceptors() {
    return Collections.unmodifiableList(interceptors);
  }

}

我们案例是拦截StatementHandler,所以也以此为例

/*
 * 这是创建StatementHandler的方法
 * Configuration#newStatementHandler
 */
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
  StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
  // 可以看到创建完StatementHandler之后,会调用InterceptorChain的pluginAll方法
  statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
  return statementHandler;
}

那么我们再仔细分析下 pluginAll方法, pluginAll调用的是每个插件的 plugin方法

default Object plugin(Object target) {
  return Plugin.wrap(target, this);
}

可以看到,最终调用的是 Plugin.*wrap*

/*
 * Plugin#wrap
 * 判断是否满足插件的拦截条件,是则返回代理类,否则返回原对象
 */
public static Object wrap(Object target, Interceptor interceptor) {
  // 获取插件的拦截信息(就是获取@Intercepts注解的内容)
  Map, Set> signatureMap = getSignatureMap(interceptor);
  Class type = target.getClass();
  // 判断是否满足拦截条件
  Class[] interfaces = getAllInterfaces(type, signatureMap);
  if (interfaces.length > 0) {
    // 满足拦截条件则返回Plugin代理对象
    return Proxy.newProxyInstance(
        type.getClassLoader(),
        interfaces,
        new Plugin(target, interceptor, signatureMap));
  }
  // 不满足则返回原对象
  return target;
}

Original: https://www.cnblogs.com/konghuanxi/p/16273614.html
Author: 王谷雨
Title: Mybatis源码解读-插件

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/583270/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 做celery异步任务处理,Django中的配置信息没加载,配置的路径环境变量用不了,导致模块频繁导入错误

    做celery异步任务处理,Django中的配置信息没加载,配置的路径环境变量用不了,导致模块频繁导入错误 在设置的异步任务中需要使用到Django配置好的配置信息,比如路径环境变…

    Linux 2023年6月15日
    0130
  • 使用Linux Deploy将闲置的安卓手机改造简易服务器

    本文将介绍我在自己闲置的小米4手机安装CentOS系统的过程。手机配置信息:MIUI 9开发版(方便ROOT)、Android 6、架构 ARMv7(arm32) 准备工作 1、手…

    Linux 2023年6月8日
    0108
  • 005.系统管理监测命令

    作者:木二 出处:http://www.cnblogs.com/itzgr/ 关于作者:云计算、虚拟化,Linux,多多交流! 本文版权归作者所有,欢迎转载,但未经作者同意必须保留…

    Linux 2023年6月7日
    0100
  • CSAPP 之 AttackLab 详解

    前言 本篇博客将会介绍 CSAPP 之 AttackLab 的攻击过程,利用缓冲区溢出错误进行代码注入攻击和 ROP 攻击。实验提供了以下几个文件,其中 ctarget 可执行文件…

    Linux 2023年6月7日
    0101
  • nand

    nand flash裸机编程第001节_NAND_FLASH操作原理第002节_NandFlash时序及初始化第003节_NandFlash的芯片id读取第004节_NandFla…

    Linux 2023年6月13日
    075
  • 软件测试基础理论(2)

    一, 为什么要进行软件测试 &#x4E3A;&#x4E86;&#x901A;&#x8FC7;&#x8F6F;&#x4EF6;&amp…

    Linux 2023年6月7日
    0114
  • 用powershell实现,管理github自动化

    用powershell实现,管理github自动化 搜索关键字如下:PowerShellForGitHub powershell 传教士 原创文章。始于 2021-02-04 允许…

    Linux 2023年6月14日
    085
  • CPU架构对redis的性能影响

    CPU架构对redis的性能影响 主流CPU架构 一个CPU处理器中通常有多个运行核心,每一个运行核心称为一个物理核,每个物理核都可以运行应用程序。每个物理核都拥有 私有的一级缓存…

    Linux 2023年5月28日
    0110
  • MySQL manager or server PID file could not be found!

    [root@centos var]# service mysqld stop MySQL manager or server PID file could not be found…

    Linux 2023年6月13日
    087
  • 正则表达式

    正则表达式 字符 作用 . 点号 匹配任意一个且只有一个字符 [] 匹配[]集合内的任意一个字符 [^] 匹配不包含^后的任意字符 星号 重复前一个字符(连续出现)0次或N次 . …

    Linux 2023年6月6日
    0114
  • maven安装及导入本地jar包

    一、maven的安装方法 1.去maven官网下载适合的版本 下载地址: 官方下载地址 2.下载后解压到任意目录 3.配置系统环境变量 M2_HOME ,值为maven解压后的目录…

    Linux 2023年6月14日
    0127
  • 我懂得了什么

    站在24岁的这个档口,没有学业又没有工作的时刻,前不着村后不着店。我觉得应该要写一些总结,虽然年仅24的我相比老人家总结不出更深刻的道理,但是现在是互联网的时代,获取知识的途径已经…

    Linux 2023年6月6日
    0104
  • Python 中 map() zip() list() 函数的介绍

    map() map(function , iterable, ….) : 依次将函数function作用在可迭代的list上,并返回对应的函数返回值,组成新的list(…

    Linux 2023年6月7日
    0106
  • 嵌入式软件架构设计-消息交互

    1、前言 在熟悉任务调度、程序分层和模块化编程关于软件架构、分层和模块设计后,除了函数调用设计中出现的情况外,还会遇到同层模块之前如何进行消息交互,通常是应用层之间。 比如一个设备…

    Linux 2023年6月7日
    0109
  • Linux基础入门笔记

    Linux内核最初只是由芬兰人林纳斯·托瓦兹(Linus Torvalds)在赫尔辛基大学上学时出于个人爱好而编写的。 Linux是一套免费使用和自由传播的类Unix操作系统,是一…

    Linux 2023年6月14日
    068
  • 机器学习学习笔记之一:K最近邻算法(KNN)

    假定数据有M个特征,则这些数据相当于在M维空间内的点 [X = \begin{pmatrix} x_{11} & x_{12} & … & x_…

    Linux 2023年6月14日
    080
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球