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 ...
随机推荐
- Linux学习笔记之linux软件包安装以及源的替换
先是软件源的替换,在刚安装的Ubuntu中会配有原先的软件源,所以如果要替换时,可在网上找与自己ubuntu相对应的软件源,比如我的ubuntu版本为12.04,所以我得找到相对应能够适用Ubuntu ...
- Spring Cloud 系列之 ZooKeeper 注册中心
什么是注册中心 服务注册中心是服务实现服务化管理的核心组件,类似于目录服务的作用,主要用来存储服务信息,譬如提供者 url 串.路由信息等.服务注册中心是微服务架构中最基础的设施之一. 注册中心可以说 ...
- JavaScript中为什么需要!!?
1. 布尔值为false的值 在JavaScript中,布尔值为 false的值有如下几个: undefined null false 0 NaN ""或''(空字符串) 2. ! ...
- Java中的不可变集合,我们换个方式理解!!!
不可变集合例: public static final ImmutableSet<String> COLOR_NAMES = ImmutableSet.of( "red" ...
- java web应用启动报错:Caused by: java.lang.ClassNotFoundException: ServletContext
ServletContext是个接口,不同的WEB容器(tomcat, jboss等)都有各自的实现. 一般是缺少servlet-api.jar包 在Java Build Path的Libraries ...
- JDBC的开发步骤
一.JDBC概述 JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问, 它由一组用Jav ...
- 高级搜索树-红黑树(RBTree)解析
目录 红黑树的定义 节点与树的定义 旋转操作 插入操作 情况1:p的兄弟u为黑色 情况2: p的兄弟u为红色 插入操作性能分析 代码实现 删除操作 情况1:x的接替者succ为红色 情况2:x的接替者 ...
- 图的DFS与BFS
图的DFS与BFS(C++) 概述 大一学生,作为我的第一篇Blog,准备记录一下图的基本操作:图的创建与遍历.请大佬多多包涵勿喷. 图可以采用邻接表,邻接矩阵,十字链表等多种储存结构进行储存,这里为 ...
- 实验室外的攻防战 UOJ#180 [树状数组]
实验室外的攻防战 UOJ#180 [树状数组] 题目 时针指向午夜十二点,约定的日子--2月28日终于到来了.随着一声枪响,伏特跳蚤国王率领着他的跳蚤大军们包围了 \(picks\) 博士所在的实验室 ...
- 汇编in和out实例解析
直接看例子: IN AL,21H 从21H端口读取一字节数据到AL IN AX,21H 从端口地址21H读取1字节数据到AL,从端口地址22H读取1字节到AH MOV DX,379HIN AL,DX ...