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)

大家都在看

  • Ubuntu下使用apt-get命令查询并安装指定版本的软件

    执行以下命令,查询软件所有的版本号 sudo apt-cache madison <package></package> 执行以下命令,安装指定版本的软件 …

    Linux 2023年6月6日
    093
  • redis 订阅与发布

    Reference: https://redisbook.readthedocs.io/en/latest/feature/pubsub.html Redis 的 SUBSCRIB…

    Linux 2023年5月28日
    099
  • Docker 安装 Redis

    docker 启动 redis 命令 docker run -p 6379:6379 –name redis -v /usr/local/docker/redis.conf:/e…

    Linux 2023年5月28日
    088
  • Ubuntu18开启默认root登录方法

    默认的Ubuntu 18.04系统在登陆界面上是不支持root用户直接登录的,但是你可以使用下面的方法让Ubuntu 18.04也支持root登录,其他类似的版本参考在Ubuntu…

    Linux 2023年6月7日
    082
  • 国产化之银河麒麟安装.NetCore-包管理器方式

    背景 某个项目需要实现基础软件全部国产化,其中操作系统指定银河麒麟,数据库使用达梦V8,CPU平台的范围包括x64、龙芯、飞腾、鲲鹏等。 考虑到这些基础产品对.NETCore的支持…

    Linux 2023年5月27日
    0112
  • 洛谷P3372–线段树代码模板1

    时空限制:1000ms,128M 数据规模: 对于30%的数据:N Original: https://www.cnblogs.com/ygsworld/p/11279732.ht…

    Linux 2023年6月7日
    0106
  • 一文搞懂 Netty 发送数据全流程 | 你想知道的细节全在这里

    欢迎关注公众号:bin的技术小屋,如果大家在看文章的时候发现图片加载不了,可以到公众号查看原文 本系列Netty源码解析文章基于 4.1.56.Final版本 在《Netty如何高…

    Linux 2023年6月6日
    084
  • 高等代数:4 矩阵的运算

    4 矩阵的运算 1、数域K上两个矩阵称为 相等,如果它们的行数相等,列数也相等,并且它们的所有元素对应相等。 2、定义1:设(A=(a_{ij}),B=(b_{ij}))都是数域K…

    Linux 2023年6月8日
    083
  • 监控平台SkyWalking9入门实践

    简便快速的完成对分布式系统的监控; 一、业务背景 微服务作为当前系统架构的主流选型,虽然可以应对复杂的业务场景,但是随着业务扩展,微服务架构本身的复杂度也会膨胀,对于一些核心的业务…

    Linux 2023年6月14日
    078
  • HTML基础笔记整理

    「学习笔记」HTML基础 勤做笔记不仅可以让自己学的扎实,更重要的是可以让自己少走弯路。有人说:”再次翻开笔记是什么感觉”,我的回答是:”初恋般…

    Linux 2023年6月13日
    076
  • HBuilderX配置外部服务器(tomcat)查看编辑jsp界面

    HBuilderX配置外部服务器(tomcat)查看编辑jsp界面 一、第一种方法,通过启动本地tomcat,查看jsp 在tomcat的webapps目录下创建文件夹HBuild…

    Linux 2023年6月7日
    071
  • 微服务架构项目搭建过程中的Mysql安装和相关问题

    搭建微服务架构的过程中需要使用Mysql数据库,Mysql数据库搭建着实不是一个容易的事情,会碰到各种各样的问题,如果没有一个安装数据库的思路真的很难把数据库安装好,并且掉入到安装…

    Linux 2023年6月14日
    0104
  • 剑指offer计划21( 位运算简单)—java

    1.1、题目1 剑指 Offer 15. 二进制中1的个数 1.2、解法 通过判断每一位的与来识别1的数量。 1.3、代码 public class Solution { // y…

    Linux 2023年6月11日
    0111
  • Spring事务(一)-事务配置

    事务是数据库操作最基本的单元,是逻辑上的一组操作,这一组操作在同一个会话中要么都执行成功,要么都失败,这也是事务的最基本特性–原子性。事务的作用是为了保证系统数据的正确…

    Linux 2023年6月6日
    077
  • POJ1611(The Suspects)–简单并查集

    1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include&lt…

    Linux 2023年6月7日
    0103
  • 2017年腾讯 秋招软件开发笔试编程题回忆版

    2017 年腾讯 秋招软件开发笔试编程题回忆版 (所有题目大致描述如下,并非完整的题目回忆,但意思大致一样) 1、又一个魔法城市,城市里面有n个魔法城堡,序号为0,1,2。。。n-…

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