Mybatis源码学习第七天(插件源码分析)
为了不把开发和源码分析混淆,决定分开写;
接下来分析一下插件的源码,说道这里老套路先说一个设计模式,他就是责任链模式
责任链模式:就是把一件工作分别经过链上的各个节点,让这些节点依次处理这个工作,和装饰器模式不同,每个节点都知道后继者是谁,适合为完成同一个请求需要多个处理类的场景;

Handler:定义了一个处理请求的标准接口;
ConcreteHandler:具体的处理者,处理他负责的部分,根据业务可以结束处理流程,也可以将请求转发给他的后继者;
client:发送者,发起请求的客户端;
责任链模式优点:
1:降低耦合度,他将请求的发送者和接受者解耦;
2:简化了对象,使得对象不需要知道链的结构;
3:增强给对象指派责任的灵活性,通过改变链内的成员或者调动他们的次序,允许动态的新增或者删除责任;
4:增加新的请求处理类很方便;
Mybatis插件模块源码分析
1:插件的初始化(XMLConfigBuilder.pluginElement);
2:插件的加载(Configuration.new*方法,四大对象的创建);
3:插件的调用(Plugin.wrap,Plugin.invoke);
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源码学习第七天(插件源码分析)的更多相关文章
- mybatis源码学习:一级缓存和二级缓存分析
目录 零.一级缓存和二级缓存的流程 一级缓存总结 二级缓存总结 一.缓存接口Cache及其实现类 二.cache标签解析源码 三.CacheKey缓存项的key 四.二级缓存TransactionCa ...
- SpringBoot源码学习1——SpringBoot自动装配源码解析+Spring如何处理配置类的
系列文章目录和关于我 一丶什么是SpringBoot自动装配 SpringBoot通过SPI的机制,在我们程序员引入一些starter之后,扫描外部引用 jar 包中的META-INF/spring. ...
- Mybatis源码学习第七天(PageHelper分析)
其实我本来是不打算写这个PageHelper的,但是后来想了想,还是写了吧!现在市场用Mybatis的产品分页应该差不多都是用PageHelper来实现的,毕竟Mybatis的分页rowbound.. ...
- 【mybatis源码学习】利用maven插件自动生成mybatis代码
[一]在要生成代码的项目模块的pom.xml文件中添加maven插件 <!--mybatis代码生成器--> <plugin> <groupId>org.mybat ...
- Mybatis源码学习第七天(插件开发原理)
插件概述: 插件是用来改变或者扩展mybatis的原有功能,mybatis的插件就是通过继承Interceptor拦截器实现的,在没有完全理解插件之前j禁止使用插件对mybatis进行扩展,有可能会导 ...
- Netty源码学习(七)FastThreadLocal
0. FastThreadLocal简介 如同注释中所说:A special variant of ThreadLocal that yields higher access performance ...
- yii2源码学习笔记(七)
今天继续了解model类 /** 2 * Returns the form name that this model class should use. 3 * 4 * 返回表单的名称,就是这个 mo ...
- 【js】vue 2.5.1 源码学习 (七) 初始化之 initState 响应式系统基本思路
大体思路(六) 本节内容: 一.生命周期的钩子函数的实现 ==> callHook(vm , 'beforeCreate') beforeCreate 实例创建之后 事件数据还未创建 二.初始化 ...
- spring源码学习(三)--spring循环引用源码学习
在spring中,是支持单实例bean的循环引用(循环依赖)的,循环依赖,简单而言,就是A类中注入了B类,B类中注入了A类,首先贴出我的代码示例 @Component public class Add ...
随机推荐
- GitLab 配置模板
GitLab 配置模板 GitLab 使用模板和参数生成配置文件. 一般来说,我们会通过 gitlab.rb 文件修改配置,例如 Nginx 相关配置. gitlab.rb 只能使用特定的几个 Ngi ...
- RIPS源码阅读记录(二)
Author: tr1ple 这部分主要分析scanner.php的逻辑,在token流重构完成后,此时ini_get是否包含auto_prepend_file或者auto_append_file 取 ...
- Python中json.dump与repr的区别
Json是一种轻量级的数据交换格式,Python3 中可以使用 json 模块来对 JSON 数据进行编解码,它包含了两个函数: 引入json包: import json json.dumps(): ...
- Android 使用AS编译出错:找不到xx/desugar/debug/66.jar (系统找不到指定的文件。)
以为是合作人配置文件的问题,后发现是缓存的问题,只需要Clean project,即可. 若提示无法删除目录:Unable to delete directory,或许是因为你打开了另一个项目,只需关 ...
- 国人开源了一款超好用的 Redis 客户端,真香!!
大家都知道,Redis Desktop Manager 是一款非常好用的 Redis 可视化客户端工具,但可惜的是 v0.9.4 版本之后需要收费了: 这个工具不再免费提供安装包了,要对所有安装包收费 ...
- 记录一下navicat的快捷键
1.ctrl+q 打开查询窗口2.ctrl+/ 注释sql语句3.ctrl+shift +/ 解除注释4.ctrl+r 运行查询窗口的s ...
- Jmeter 常用函数(31)- 详解 __iterationNum
如果你想查看更多 Jmeter 常用函数可以在这篇文章找找哦 https://www.cnblogs.com/poloyy/p/13291704.html 作用 获取当前线程的循环次数,跟线程组属性挂 ...
- 团队作业3:需求改进&系统设计(歪瑞古德小队)
目录 一.需求&原型改进 1.1 用户需求调查 1.2 选题需求改进 1.3 功能分析的四个象限 1.4 完善需求规格说明书 1.5 任务分解WBS调整 1.6 项目进度计划调整 二.后端架构 ...
- 喵的Unity游戏开发之路 - 在球体上行走
很多童鞋没有系统的Unity3D游戏开发基础,也不知道从何开始学.为此我们精选了一套国外优秀的Unity3D游戏开发教程,翻译整理后放送给大家,教您从零开始一步一步掌握Unity3D游戏开发. 本文不 ...
- 焦大:seo思维进化论(中)
http://www.wocaoseo.com/thread-52-1-1.html 给你一个网站,你第一步做的是什么?我觉得这个是一个绝好的问题,但是却也是个难题,最常见的答案是莫过于做修改标题/查 ...