MyBatis源码中的设计模式1

1. 建造者模式的应用

建造者模式属于创建类模式,通过一步一步地创建一个复杂的对象,能够将部件与其组装过程分开。用户只需指定复杂对象的类型,就可以得到该对象,而不需要了解其内部的具体构造细节。《Effective Java》中也提到,遇到多个构造器参数时,考虑用构建者(Builder)模式。

在 Mybatis 的环境初始化过程中,SqlSessionFactoryBuilder会调用XMLConfigBuilder读取所有的MybatisMapConfig.xml和所有的*Mapper.xml文件,构建 Mybatis 运行的核心对象Configuration对象,然后将该Configuration对象作为参数构建一个SqlSessionFactory对象。

示例图

在这里插入图片描述

其中,XMLConfigBuilder在构建Configuration对象时,也会调用XMLMapperBuilder用于读取*.Mapper文件,而XMLMapperBuilder会使用XMLStatementBuilder来读取和构建所有的 SQL 语句。

示例图

在这里插入图片描述

在这个过程中,Builder模式会读取文件或者配置,然后做大量的 XPath 解析、配置或语法解析、反射生成对象、存入结果缓存等步骤。因此,大量采用了 Builder 模式来解决这些问题。

对于Builder的具体类,方法大都用build*开头,比如SqlSessionFactoryBuilder类中包含的方法:

示例图

在这里插入图片描述

从建造者模式的设计初衷来看,SqlSessionFactoryBuilder虽然带有 Builder 后缀,但不完全是标准的建造者模式。它的设计初衷是为了简化开发,隐藏构建SqlSessionFactory的复杂过程,对程序员透明。

2. 工厂模式的应用

在 Mybatis 中,SqlSessionFactory使用了简单工厂模式。

简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。简单工厂模式中,可以根据参数的不同返回不同类的实例。

示例图

在这里插入图片描述

SqlSession是 Mybatis 工作的核心接口,通过这个接口可以执行 SQL 语句、获取 Mappers、管理事务。

示例图

在这里插入图片描述

DefaultSqlSessionFactory的默认工厂实现里,openSessionFromDataSource方法展示了工厂如何产出一个产品:

示例图

在这里插入图片描述

这个方法会先从configuration读取对应的环境配置,然后初始化TransactionFactory获得一个Transaction对象,通过Transaction获取一个Executor对象,最后通过configurationExecutorautoCommit参数构建了SqlSession

3. 代理模式的应用

代理模式是 Mybatis 核心使用的模式,使我们只需要编写Mapper.java接口,不需要实现,由 Mybatis 背后完成具体 SQL 的执行。

代理模式(Proxy Pattern):给某个对象提供一个代理,并由代理对象控制对原对象的引用。

示例图

在这里插入图片描述

每次调用sqlSessiongetMapper方法时,都会创建一个新的动态代理类实例。

示例图

在这里插入图片描述

当我们使用ConfigurationgetMapper方法时,会调用mapperRegistry.getMapper方法,

示例图

在这里插入图片描述

在这里,通过T newInstance(SqlSession sqlSession)方法得到一个MapperProxy对象,然后调用T newInstance(MapperProxy<T> mapperProxy)生成代理对象。

示例图

在这里插入图片描述

通过这种方式,我们只需要编写Mapper.java接口类,实际执行时会转发给MapperProxy.invoke方法,调用后续的sqlSession.cud > executor.execute > prepareStatement等方法,完成 SQL 的执行和返回。

4. 模板方法模式的应用

在 Mybatis 中,sqlSession的 SQL 执行委托给Executor实现,Executor包含以下结构:

示例图

在这里插入图片描述

其中的BaseExecutor采用了模板方法模式,实现了大部分的 SQL 执行逻辑,把几个方法交给子类定制化完成。

示例图

在这里插入图片描述

模板模式基于继承实现代码复用。抽象类中包含模板方法,调用有待子类实现的抽象方法。

5. 装饰者模式的应用

装饰模式(Decorator Pattern):动态地给一个对象增加一些额外的职责,比生成子类实现更为灵活。

在 Mybatis 中,缓存功能由根接口Cache定义,采用装饰器设计模式,数据存储和缓存的基本功能由PerpetualCache实现,然后通过一系列的装饰器来对PerpetualCache进行缓存策略等方面的控制。

示例图

在这里插入图片描述

用于装饰PerpetualCache的标准装饰器有:

  1. FifoCache
  2. LoggingCache
  3. LruCache
  4. ScheduledCache
  5. SerializedCache
  6. SoftCache
  7. SynchronizedCache
  8. WeakCache

Mybatis 采用装饰器模式实现缓存功能,通过组合而非继承,更加灵活,避免了继承关系的组合爆炸。

6. 迭代器模式的应用

迭代器模式介绍

  • 迭代器模式是一个行为型设计模式,用于在不暴露其底层表示的情况下顺序访问集合对象的元素。在大多数编程语言中,迭代器已经成为基础的类库,直接用来遍历集合对象。在日常开发中,我们通常直接使用现有的迭代器,而不需要从零实现一个。
  • 在软件系统中,容器对象有两个职责:存储数据和遍历数据。从依赖性角度看,前者是聚合对象的基本职责,后者是可变化且可分离的。因此,可以将遍历数据的行为从容器中抽取出来,封装到迭代器对象中,由迭代器提供遍历数据的功能。这将简化聚合对象的设计,更加符合单一职责原则。

在这里插入图片描述

迭代器模式主要包含以下角色:

  1. 抽象集合(Aggregate)角色:用于存储和管理元素对象,定义存储、添加、删除集合元素的功能,并声明一个 createIterator() 方法用于创建迭代器对象。
  2. 具体集合(ConcreteAggregate)角色:实现抽象集合类,返回一个具体迭代器的实例。
  3. 抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()next() 等方法。
    • hasNext() 方法用于判断集合中是否还有下一个元素。
    • next() 方法用于将游标后移一位元素。
    • currentItem() 方法用于返回当前游标指向的元素。
  4. 具体迭代器(ConcreteIterator)角色:实现抽象迭代器接口中定义的方法,完成对集合对象的遍历,同时记录遍历的当前位置。

在Java中,Iterator接口就是迭代器模式的实现,只要实现了该接口,就相当于应用了迭代器模式:

在这里插入图片描述

迭代器模式总结

使用场景

  1. 访问一个聚合对象的内容,不需要暴露它的内部表示。
  2. 支持对聚合对象的多种遍历。
  3. 迭代器模式与集合同时存在。

优点

  1. 支持以不同的方式遍历一个聚合对象,在同一个聚合对象上可以定义多种遍历方式。
  2. 迭代器简化了聚合类。引入迭代器模式后,聚合对象不再需要自行提供数据遍历访问的方法。
  3. 可以为不同的聚合结构提供一个统一的接口。

缺点

  1. 迭代器模式将存储数据和遍历数据的职责分离开,增加新的聚合类型需要增加对应的新迭代器类,增加了系统复杂性。

MyBatis中的应用

MyBatis的 PropertyTokenizer 是 property 包中的重要类,它实现了 Iterator 接口,并在 reflection 包中的其他类中被频繁引用。该类的 hasNext() 方法经常被使用。

/*** 属性分词器* * 实现 Iterator 接口,用于遍历属性的各个部分*/
public class PropertyTokenizer implements Iterator<PropertyTokenizer> {private String name;private final String indexedName;private String index;private final String children;public PropertyTokenizer(String fullname) {int delim = fullname.indexOf('.');if (delim > -1) {name = fullname.substring(0, delim);children = fullname.substring(delim + 1);} else {name = fullname;children = null;}indexedName = name;delim = name.indexOf('[');if (delim > -1) {index = name.substring(delim + 1, name.length() - 1);name = name.substring(0, delim);}}public String getName() {return name;}public String getIndex() {return index;}public String getIndexedName() {return indexedName;}public String getChildren() {return children;}@Overridepublic boolean hasNext() {return children != null;}@Overridepublic PropertyTokenizer next() {return new PropertyTokenizer(children);}@Overridepublic void remove() {throw new UnsupportedOperationException("Remove is not supported, as it has no meaning in the context of properties.");}
}

这个类传入一个字符串到构造函数,然后提供了 iterator 方法对解析后的子串进行遍历,是一个非常常用的方法类。

PropertyTokenizer 类虽然实现了 Iterator 接口,但并非标准的迭代器类。它将配置解析、解析后的元素、迭代器这三部分本应分开的代码耦合在一起,因此略显复杂。不过,这样做的好处是能够实现惰性解析,不需要事先将整个配置解析成多个 PropertyTokenizer 对象,只有在调用 next() 方法时才会解析部分配置。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/378680.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenCV教程04:结合pillow在图片上显示中文文字

1.如果添加的内容是纯英文文字&#xff0c;直接使用cv2.putText 函数操作即可。但它不支持自定义字体文件&#xff0c;仅限于这些内置的字体样式。如果你需要更复杂的字体支持&#xff0c;可能需要使用其他库&#xff0c;如 Python Imaging Library (PIL) 或 Pillow。可用的字体…

Docker-Nvidia(NVIDIA Container Toolkit)

安装NVIDIA Container Toolkit工具&#xff0c;支持docker使用GPU 目录 1.NVIDIA Container Toolkit 安装1.1 nvidia-docker安装1.2 验证1.2.1 验证安装1.2.2 额外补充 1.NVIDIA Container Toolkit 安装 1.1 nvidia-docker安装 NVIDIA/nvidia-docker Installing the NVIDIA …

【BUG】已解决:java.lang.IllegalStateException: Duplicate key

已解决&#xff1a;java.lang.IllegalStateException: Duplicate key 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市…

线程控制

对线程的控制思路和进程相似&#xff0c;创建、等待、终止&#xff0c;只需要调用接口就行。但是在Linux下没有线程的概念&#xff0c;因为Linux的设计者认为&#xff0c;线程是一种轻量级的进程&#xff0c;毕竟创建线程只需要创建PCB。因此Linux中使用多线程必须使用第三方pt…

聊一聊前后端权限控制 RBAC(完整流程)

介绍 RBAC&#xff08;Role-Based Access Control&#xff09;模型也就是基于角色的权限控制。 权限会分配到角色中&#xff0c;角色再分配给用户&#xff0c;这样用户就根据角色有了不同的权限。 当然&#xff0c;你可以说把权限直接挂载到用户上&#xff0c;这样不是更直接…

前端工程化10-webpack静态的模块化打包工具之各种loader处理器

9.1、案例编写 我们创建一个component.js 通过JavaScript创建了一个元素&#xff0c;并且希望给它设置一些样式&#xff1b; 我们自己写的css,要把他加入到Webpack的图结构当中&#xff0c;这样才能被webpack检测到进行打包&#xff0c; style.css–>div_cn.js–>main…

代码随想录二刷复习(二分法)

二分法模板&#xff1a; 1&#xff1a;左闭右闭区间写法 第一种写法&#xff0c;我们定义 target 是在一个在左闭右闭的区间里&#xff0c;也就是[left, right] &#xff08;这个很重要非常重要&#xff09;。 区间的定义这就决定了二分法的代码应该如何写&#xff0c;因为定…

泛微e-cology WorkflowServiceXml SQL注入漏洞(POC)

漏洞描述&#xff1a; 泛微 e-cology 是泛微公司开发的协同管理应用平台。泛微 e-cology v10.64.1的/services/接口默认对内网暴露&#xff0c;用于服务调用&#xff0c;未经身份认证的攻击者可向 /services/WorkflowServiceXml 接口发送恶意的SOAP请求进行SQL注入&#xff0c;…

Web渗透:Shiro550漏洞(CVE-2016-4437)

Apache Shiro 是一个强大且易于使用的Java安全框架&#xff0c;提供了身份验证&#xff08;Authentication&#xff09;、授权&#xff08;Authorization&#xff09;、会话管理&#xff08;Session Management&#xff09;和密码学支持等功能。Apache Shiro 550反序列化漏洞&a…

AI算法19-偏最小二乘法回归算法Partial Least Squares Regression | PLS

偏最小二乘法回归算法简介 算法概述 偏最小二乘法模型可分为偏最小二乘回归模型和偏最小二乘路径模型。其中偏最小二乘回归模型是一种新型的多元统计方法&#xff0c;它集中了主成分分析、典型相关分析和线性回归的特点&#xff0c;特别在解决回归中的共线性问题具有无可比拟…

内网安全:权限维持的各种姿势

1.Linux权限维持 2.Windows权限维持 目录&#xff1a; 一.Linux权限维持&#xff1a; 1.webshell&#xff1a; 2.定时任务&#xff1a; 3.SUID后门&#xff1a; 4.SSH Key免密登录后门&#xff1a; 5.添加用户后门&#xff1a; 二.Windows权限维持 1.计划任务后门&…

记录些Spring+题集(1)

接口防刷机制 接口被刷指的是同一接口被频繁调用&#xff0c;可能是由于以下原因导致&#xff1a; 恶意攻击&#xff1a;攻击者利用自动化脚本或工具对接口进行大量请求&#xff0c;以消耗系统资源、拖慢系统响应速度或达到其他恶意目的。误操作或程序错误&#xff1a;某些情…

iOS ------ 消息传递和消息转发

一&#xff0c;消息传递 在OC中&#xff0c;传递消息就是在对象上调用方法。 相对于C语言的方法就“静态绑定”的函数&#xff0c;在编译器就决定了运行时所要调用的函数。在OC中&#xff0c;如果向某对象传递消息&#xff0c;就会使用动态绑定机制来决定需要调用那个方法。调…

【操作系统】定时器(Timer)的实现

这里写目录标题 定时器一、定时器是什么二、标准库中的定时器三、实现定时器 定时器 一、定时器是什么 定时器也是软件开发中的⼀个重要组件.类似于⼀个"闹钟".达到⼀个设定的时间之后,就执行某个指定 好的代码. 定时器是⼀种实际开发中⾮常常用的组件. ⽐如⽹络通…

浅谈C嘎嘎类与对象

本篇文章与大家浅谈一下C嘎嘎的类与对象知识点 类的定义 关键字&#xff1a;class 语法格式&#xff1a; class 类名 { }&#xff1b;//这里的分号不能少 此外&#xff0c;class有三个属性分别是private、public、protected&#xff0c;这三个属性是干啥的&#xff0c;相…

FPGA CFGBVS 管脚接法

说明 新设计了1个KU040 FPGA板子&#xff0c;回来之后接上JTAG FPGA不识别。做如下检查&#xff1a; 1、电源测试点均正常&#xff1b; 2、查看贴片是否有漏焊&#xff0c;检查无异常&#xff0c;设计上NC的才NC&#xff1b; 3、反复检查JTAG接线是否异常&#xff0c;贴片是…

【BUG】已解决:ValueError: Expected 2D array, got 1D array instead

已解决&#xff1a;ValueError: Expected 2D array, got 1D array instead 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉…

本地多模态看图说话-llava

其中图片为bast64转码&#xff0c;方便json序列化。 其中模型llava为本地ollama运行的模型&#xff0c;如&#xff1a;ollama run llava 还有其它的模型如&#xff1a;llava-phi3&#xff0c;通过phi3微调过的版本。 实际测试下来&#xff0c;发现本地多模型的性能不佳&…

音视频入门基础:H.264专题(13)——FFmpeg源码中通过SPS属性获取视频色彩格式的实现

一、引言 通过FFmpeg命令可以获取到H.264裸流文件的色彩格式&#xff08;又译作色度采样结构、像素格式&#xff09;&#xff1a; 在vlc中也可以获取到色彩格式&#xff08;vlc底层也使用了FFmpeg进行解码&#xff09;&#xff1a; 这个色彩格式就是之前的文章《音视频入门基础…

【unity实战】使用unity制作一个红点系统

前言 注意&#xff0c;本文是本人的学习笔记记录&#xff0c;这里先记录基本的代码&#xff0c;后面用到了再回来进行实现和整理 素材 https://assetstore.unity.com/packages/2d/gui/icons/2d-simple-ui-pack-218050 框架&#xff1a; RedPointSystem.cs using System.…