为了不把开发和源码分析混淆,决定分开写;

接下来分析一下插件的源码,说道这里老套路先说一个设计模式,他就是责任链模式

责任链模式:就是把一件工作分别经过链上的各个节点,让这些节点依次处理这个工作,和装饰器模式不同,每个节点都知道后继者是谁,适合为完成同一个请求需要多个处理类的场景;

Handler:定义了一个处理请求的标准接口;

ConcreteHandler:具体的处理者,处理他负责的部分,根据业务可以结束处理流程,也可以将请求转发给他的后继者;

client:发送者,发起请求的客户端;

责任链模式优点:

1:降低耦合度,他将请求的发送者和接受者解耦;

2:简化了对象,使得对象不需要知道链的结构;

3:增强给对象指派责任的灵活性,通过改变链内的成员或者调动他们的次序,允许动态的新增或者删除责任;

4:增加新的请求处理类很方便;

Mybatis插件模块源码分析

1:插件的初始化(XMLConfigBuilder.pluginElement);

2:插件的加载(Configuration.new*方法,四大对象的创建);

3:插件的调用(Plugin.wrap,Plugin.invoke);

Mybatis插件理解

pluginElement(root.evalNode("plugins"));//从这行代码开始解析插件节点

 /**
* 解析所有的插件节点
* @param parent
* @throws Exception
*/
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();
// 设置插件的属性 所以在插件中才可以得到XML中配置的属性
interceptorInstance.setProperties(properties);
// 将插件添加到configuration中 底层采用list保存所有的插件并记录顺序
// InterceptorChain 存在的类
// private final List<Interceptor> interceptors = new ArrayList<>();
configuration.addInterceptor(interceptorInstance);
}
}
}

其实在这里也不是经典的责任链模式,就像tomcat的filter一样,他并不知道自己的下一个节点是谁,他的顺序是由配置决定的由上而下的;其实这样演变也是有好处的就是解开了下级节点和当前节点的耦合,完全由配置决定;

 public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
// 如果存在<cache>节点 那么通过装饰器CachingExecutor 包装原始的executor
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
// 通过InterceptorChain遍历所有的插件为Executor增强,添加插件的功能
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
 public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
// 这里调用的就是实现interceptor接口实现的plugin方法 传入目标对象
target = interceptor.plugin(target);
}
return target;
}

接下来看一下实现类中的plugin方法,在接口中可以定义默认方法实现之后我们的实现类中已经不需要重写plugin方法 了我们看一下接口中的

 /**
*
* @param target 被拦截的对象,他的作用就是给拦截的对象生成一个代理对象
* @return
*/
default Object plugin(Object target) {
return Plugin.wrap(target, this);
}
 /**
* 静态方法,用于帮助Interceptor生成动态代理
* @param target
* @param interceptor
* @return
*/
public static Object wrap(Object target, Interceptor interceptor) {
// 解析Interceptor上标志的@Intercepts注解得到的Signature信息
Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor);
// 获取目标对象的类型
Class<?> type = target.getClass();
// 获取目标对象实现的接口,拦截器可以拦截4大对象实现的接口
Class<?>[] interfaces = getAllInterfaces(type, signatureMap);
if (interfaces.length > 0) {
// 使用JDK动态代理
return Proxy.newProxyInstance(
type.getClassLoader(),
interfaces,
new Plugin(target, interceptor, signatureMap));
}
return target;
}

至于Plugin.invoke就是调用的我们实现的Interceptor接口的intercept方法;

作者:彼岸舞

时间:2020\03\24

内容关于:Mybatis

本文部分来源于网络,只做技术分享,一概不负任何责任

Mybatis源码学习第七天(插件源码分析)的更多相关文章

  1. mybatis源码学习:一级缓存和二级缓存分析

    目录 零.一级缓存和二级缓存的流程 一级缓存总结 二级缓存总结 一.缓存接口Cache及其实现类 二.cache标签解析源码 三.CacheKey缓存项的key 四.二级缓存TransactionCa ...

  2. SpringBoot源码学习1——SpringBoot自动装配源码解析+Spring如何处理配置类的

    系列文章目录和关于我 一丶什么是SpringBoot自动装配 SpringBoot通过SPI的机制,在我们程序员引入一些starter之后,扫描外部引用 jar 包中的META-INF/spring. ...

  3. Mybatis源码学习第七天(PageHelper分析)

    其实我本来是不打算写这个PageHelper的,但是后来想了想,还是写了吧!现在市场用Mybatis的产品分页应该差不多都是用PageHelper来实现的,毕竟Mybatis的分页rowbound.. ...

  4. 【mybatis源码学习】利用maven插件自动生成mybatis代码

    [一]在要生成代码的项目模块的pom.xml文件中添加maven插件 <!--mybatis代码生成器--> <plugin> <groupId>org.mybat ...

  5. Mybatis源码学习第七天(插件开发原理)

    插件概述: 插件是用来改变或者扩展mybatis的原有功能,mybatis的插件就是通过继承Interceptor拦截器实现的,在没有完全理解插件之前j禁止使用插件对mybatis进行扩展,有可能会导 ...

  6. Netty源码学习(七)FastThreadLocal

    0. FastThreadLocal简介 如同注释中所说:A special variant of ThreadLocal that yields higher access performance ...

  7. yii2源码学习笔记(七)

    今天继续了解model类 /** 2 * Returns the form name that this model class should use. 3 * 4 * 返回表单的名称,就是这个 mo ...

  8. 【js】vue 2.5.1 源码学习 (七) 初始化之 initState 响应式系统基本思路

    大体思路(六) 本节内容: 一.生命周期的钩子函数的实现 ==> callHook(vm , 'beforeCreate') beforeCreate 实例创建之后 事件数据还未创建 二.初始化 ...

  9. spring源码学习(三)--spring循环引用源码学习

    在spring中,是支持单实例bean的循环引用(循环依赖)的,循环依赖,简单而言,就是A类中注入了B类,B类中注入了A类,首先贴出我的代码示例 @Component public class Add ...

随机推荐

  1. MySql实现 split

    substring_index(str,delim,count)       str:要处理的字符串       delim:分隔符       count:计数 例子:str=www.baidu.c ...

  2. Django-Model模型Field选项中null和blank的区别

    - Option-**blank**设置为True时代表填写表单的时候可以为空,即在save()执行时此字段可以没有,如果字段没有就在数据库上存储一个空字符串: - Option-**null**设置 ...

  3. 2020-07-24:聊一下zookeeper的同步算法。

    福哥答案2020-07-24: 同步算法基于 ZAB 协议,一种快速 Paxos 算法. 快速Paxos算法Paxos算法可能出现死循环,就是在两个Proposer总是在交替prepare.并且,Pa ...

  4. java中三大集合框架

    一.List集合 1.List实现的超级父类接口:Collection 存储一组不唯一(允许重复),有序的对象. 2.了解ArrayList类 A):定义的格式:ArrayList<具体类型&g ...

  5. Spring事务专题(五)聊聊Spring事务到底是如何实现的

    前言 本专题大纲: 本文为本专题倒数第二篇文章. 在上篇文章中我们一起学习了Spring中的事务抽象机制以及动手模拟了一下Spring中的事务管理机制,那么本文我们就通过源码来分析一下Spring中的 ...

  6. javaWeb项目之图书管理系统(附视频讲解)

    视频播放地址:javaWeb图书系统 本系统为"Swing项目之图书管理系统"(此源码已共享)的Web版,网页框架用采用EasyUI 数据库为MysqL,写Web项目摒弃了火狐浏览 ...

  7. TCP协议中的三次握手和四次挥手(图解)-转

    转自:http://blog.csdn.net/whuslei/article/details/6667471/ 建立TCP需要三次握手才能建立,而断开连接则需要四次握手.整个过程如下图所示: 先来看 ...

  8. 2.Oracle数据库安装教程

    一.准备安装 基本都是按部就班. 使用的OS版本:OEL4 安装程序路径: /mnt/Oracle11g_linux_x86_64/database 创建用户 使用的.bash_profile 修改的 ...

  9. HDFS的数据流读写数据 (面试开发重点)

    1 HDFS写数据流程 1.1 剖析文件写入 HDFS写数据流程,如图所示 1)客户端通过Distributed FileSystem模块向NameNode请求上传文件,NameNode检查目标文件是 ...

  10. 喵的Unity游戏开发之路 - 轨道摄像机

    前言        很多童鞋没有系统的Unity3D游戏开发基础,也不知道从何开始学.为此我们精选了一套国外优秀的Unity3D游戏开发教程,翻译整理后放送给大家,教您从零开始一步一步掌握Unity3 ...