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

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

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

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. 基于.NetCore3.1系列 —— 日志记录之日志核心要素揭秘

    一.前言 在上一篇中,我们已经了解了内置系统的默认配置和自定义配置的方式,在学习了配置的基础上,我们进一步的对日志在程序中是如何使用的深入了解学习.所以在这一篇中,主要是对日志记录的核心机制进行学习说 ...

  2. 谈谈集成测试(integration testing)

    对于软件开发来说,软件测试是一个几乎贯穿所有阶段的活动,所以测试的重要性毋庸置疑.不同开发组织如何在不同的产品研发阶段进行测试,也在很大程度上反映了其研发能力和质量控制能力.软件测试有很多类型,包括单 ...

  3. 谁来教我渗透测试——黑客必须掌握的HTML基础(一)

    小伙伴们,好几天不见了,这一周菜鸟小白工作很忙,所以没有每天更新学习内容,但是菜鸟小白的学习是没有停下来的,只是没有时间来整理学习笔记了.现在就将菜鸟小白这两天学习的HTML基础和大家分享,其中还会拿 ...

  4. go 字符串

    目录 前言 1.声明/赋值 2.遍历 3.操作 1.截取 2.修改 3.连接 4.比较 5.查长 6.格式化输出 4.字符串优势 跳转 前言 不做文字的搬运工,多做灵感性记录 这是平时学习总结的地方, ...

  5. Exception processing template "success": Exception parsing document: template="success",

    代码很简单 package com.kele.controller; import org.springframework.stereotype.Controller;import org.sprin ...

  6. 碰到 Json_CSRF 怎么办?

    前言 在最近挖洞的时候,老是碰到 POST 传参采用 JSON 格式,而不是传统的parameter=value的格式,之前也没接触过,所以也不知道该怎么搞,所以打算学习一下,此文作为一个笔记梳理. ...

  7. 《Java从入门到失业》第二章:Java环境(一):Java SE安装

    从这一章开始,终于我们可以开始正式进入Java世界了.前面我们提到过,Java分三个版本,我们这里只讨论Java SE. 2.1Java SE安装 所谓工欲善其事,必先利其器.第一步,我们当然是要下载 ...

  8. 输入url后的加载过程~

    1)查找域名对应的IP地址: 2)建立连接(TCP的三次握手): 3)构建网页: 4)断开连接(TCP的四次挥手): TCP的三次握手:为了准确无误的把数据送到目标处,TCP协议采用了三次握手策略,用 ...

  9. docker入门4-docker stack

    stack介绍 stack是一组共享依赖,可以被编排并具备扩展能力的关联service.举例来说就是在swarm那章描述docker层次架构时,说stack就是一个完整的服务--它可以由基于flask ...

  10. install-newton部署安装--------计算节点部署安装

    #################################################################################################### ...