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)

大家都在看

  • 5.4 Linux Vim基本操作

    《Vim三种工作模式》一节给大家详细介绍了 Vim 的 3 种工作模式,本节来学习如何使用 Vim 编辑文件。 首先学习如何使用 Vim 打开文件。 Vim 打开文件 使用 Vim…

    Linux 2023年6月7日
    0101
  • JPA作持久层操作

    JPA(Hibernate是jpa的实现) jpa是对实体类操作,从而通过封装好的接口直接设置数据库的表结构。虽然jpa可以直接通过编写java代码来操作数据库表结构,避免了sql…

    Linux 2023年6月7日
    0118
  • java反射机制

    1..获取Class实例的方式 1 @Test 2 public void test3() throws ClassNotFoundException { 3 //方式一:调用运行…

    Linux 2023年6月6日
    0123
  • spring-data-redis 2.0 的使用

    在使用Spring Boot2.x运行Redis时,发现百度不到顺手的文档,搞通后发现其实这个过程非常简单和简洁,觉得有必要拿出来分享一下。 Spring Boot2.x 不再使用…

    Linux 2023年5月28日
    0118
  • 课间游戏志:斗荧光笔与扒撸咔嚓

    课间游戏志:斗荧光笔与扒撸咔嚓 写这篇博客,主要是想记录两个课间游戏,一个是我于小学四年级时发明的斗荧光笔,一个是初中时班上几个变态发明的扒撸咔嚓,自从这两个游戏被发明以后,我们班…

    Linux 2023年6月6日
    0104
  • 为Linux系统添加定时备份Mysql(Docker)指定数据库的方法

    引言使用Mysql的时候遇到需要定时备份数据库的问题,但苦于Mysql自身没有提供直接的工具。 安装7z的目的主要是用于对数据库备份后的文件的压缩和加密。如果不需要也可以跳过此步骤…

    Linux 2023年6月14日
    0109
  • Netty源码解读(三)-NioEventLoop

    先看看EventLoop类图 我们在Netty第二篇文章中的代码中,看到有多次用到eventLoop.execute()方法,这个方法就是EventLoop开启线程执行任务的关键,…

    Linux 2023年6月7日
    095
  • Linux系统编程001–系统IO

    1. 文件系统:用来存储、组织、管理文件的一套方式、协议 2. 文件 文件的属性:i-node唯一表示一个文件的存在与否 文件的内容 3. Linux系统如何实现文件的操作? &a…

    Linux 2023年6月6日
    096
  • Ubuntu 进程 线程 查看 设置(top taskset)

    top 的基本使用 taskset 的基本使用 top top 详解 及 使用 top 常用的命令 taskset taskset 的基本使用 1. 显示某个进程(线程)运行所在的…

    Linux 2023年6月6日
    0118
  • 分布式系统中数据存储方案实践

    数据膨胀的时候,必然放大细节。 一、背景简介 在项目研发的过程中,对于数据存储能力的依赖无处不在,项目初期,相比系统层面的组件选型与框架设计,由于数据体量不大,在存储管理方面通常容…

    Linux 2023年6月14日
    085
  • 【Leetcode】768. 最多能完成排序的块 II

    arr是一个可能包含重复元素的整数数组,我们将这个数组分割成几个”块”,并将这些块分别进行排序。之后再连接起来,使得连接的结果和按升序排序后的原数组相同。 …

    Linux 2023年6月6日
    092
  • Java基础系列–01_基础类型

    J2SE、J2ME、J2EE分别指什么?J2SE 基础版,桌面应用。J2ME 微型版,手机开发。(android,ios)J2EE 企业版,所有浏览器访问的应用程序。注意:JDK5…

    Linux 2023年6月7日
    0101
  • phpcms全文检索功能实现(集成sphinx)

    sphinx配置 sphinx是俄罗斯人开发的一个搜索引擎,基于c++编写,具有强大的检索能力,本身支持中文单个字符的检索,中文分词需要额外的插件Coreseek,但该插件已很久未…

    Linux 2023年6月13日
    0123
  • Linux 0.11源码阅读笔记-总结

    Linux 0.11主要包含文件管理和进程管理两个部分。进程管理包括内存管理、进程管理、进程间通信模块。文件管理包含磁盘文件系统,打开文件内存数据。磁盘文件系统包括空闲磁盘块管理,…

    Linux 2023年5月27日
    082
  • 《Kali Linux高级渗透测试原书第2版》网络渗透测试技术书 无线网络渗透测试详解 黑客攻击与防范实战从入门到精通书

    Original: https://www.cnblogs.com/bnn86/p/15380679.htmlAuthor: 测试楠楠君Title: 《Kali Linux高级渗透…

    Linux 2023年5月27日
    0109
  • ASP.NET Core 2.2 : 二十一. 内容协商与自定义IActionResult和格式化类

    上一章的结尾留下了一个问题:同样是ObjectResult,在执行的时候又是如何被转换成string和JSON两种格式的呢? 本章来解答这个问题,这里涉及到一个名词:”…

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