当前位置: 首页 > news >正文

【Mybatis源码分析】TypeAliasRegistry源码分析

TypeAliasRegistry源码分析

  • 一、引入类型别名
  • 二、typeAlias 的三种配置方式
  • 三、TypeAliasRegistry源码分析
    • 三种配置方式源码解析
    • 校验过程
    • Mybatis默认的别名配置
  • 四、总结

一、引入类型别名

当配置 XML 文件,需要指明Java类型时,类型别名可替代Java类型的全名,一般会设置一个简单缩写的类型别名去替代它,用于XML配置,以降低冗余的全限定类名书写。(说白了其作用就是偷懒)

下面是使用全限定类名指定的配置:

    <select id="selectAll" resultType="com.ncpowernode.mybatis.bean.User">select * from t_user;</select>

当在核心配置文件中配置完后:

在这里插入图片描述
即可写成下面的形式:

<select id="selectAll" resultType="user">select * from t_user;
</select>

二、typeAlias 的三种配置方式

  1. type属性和alias属性双搭
<typeAlias type="com.ncpowernode.mybatis.bean.User" alias="user"/>
  1. 直接写type属性指定全限定类名,底层会利用该类的simpleName去当作这个alias。
<typeAlias type="com.ncpowernode.mybatis.bean.User"/>
  1. 直接配置包标签,使得指定包下的所有类都进行别名配置。
<package name="com.ncpowernode.mybatis.bean"/>

三、TypeAliasRegistry源码分析

三种配置方式源码解析

Mybatis通过TypeAliasRegistry对象实现对别名的封装,实现别名对应Java类型的校验。TypeAliasRegistry类中是用一Map成员对象实现上面封装效果的。

public class TypeAliasRegistry {// key对应着别名,Class对应着全限定类名转换的Class对象private final Map<String, Class<?>> typeAliases = new HashMap<>();
}

解析核心配置文件时候支持上面提到的三种设置别名的方式,那自然底层实现也存在三种,但万变不理其中,最后跳转到的代码(核心方法)如下所示:

  public void registerAlias(String alias, Class<?> value) {//判断别名是否为空if (alias == null) {throw new TypeException("The parameter alias cannot be null");}// 将别名都转换为小写存储,利于后续进行校验String key = alias.toLowerCase(Locale.ENGLISH);// 从这段代码可以知道别名可以支持多个对应一个Class对象if (typeAliases.containsKey(key) && typeAliases.get(key) != null && !typeAliases.get(key).equals(value)) {throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + typeAliases.get(key).getName() + "'.");}// 封装到Map中typeAliases.put(key, value);}

下面对三种方式源码进行解析

  • 第一种:type和alias属性双用(直接跳转到上面核心方法)
  public void registerAlias(String alias, String value) {registerAlias(alias, Resources.classForName(value));}
  • 第二种:仅用type属性(熟知的简单类名,为什么是简单类名当作别名下面的代码很好的体现出来了,还有一种设置别名的方式是使用@Alias注解,但小编本人不喜欢用)
  public void registerAlias(Class<?> type) {// 获取类中的简单类名称,充当别名String alias = type.getSimpleName();// 如果在对应类上用了@Alias注解的话,那对应的是@Alias注解中的value属性值// 但小编不建议用,出错了感觉不好排查Alias aliasAnnotation = type.getAnnotation(Alias.class);if (aliasAnnotation != null) {alias = aliasAnnotation.value();}// 进行封装registerAlias(alias, type);}
  • 第三种:使用package标签(常用)
  public void registerAliases(String packageName) {registerAliases(packageName, Object.class);}public void registerAliases(String packageName, Class<?> superType) {ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();// 获取包下的类Class对象,仅该目录下的,子目录下的类对象不包括resolverUtil.find(new ResolverUtil.IsA(superType), packageName);Set<Class<? extends Class<?>>> typeSet = resolverUtil.getClasses();for (Class<?> type : typeSet) {// 对应的类不能是匿名类/接口if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {// 本质是使用第二种方式registerAlias(type);}}}

校验过程

通过阅读下面源码可以知道:

  1. 为什么使用别名的时候各个字符不区分大小写;
  2. 为什么使用别名也行,使用全限定类名也行。
  public <T> Class<T> resolveAlias(String string) {try {// 判断传来的别名(也可能是全限定类名)不为空if (string == null) {return null;}// 解析的时候都会转换成小写// 这就是为什么使用别名的时候别名字母小写大写无所谓String key = string.toLowerCase(Locale.ENGLISH);Class<T> value;if (typeAliases.containsKey(key)) {// 通过别名查找对应的value(Class对象)value = (Class<T>) typeAliases.get(key);} else {// 无别名就当作全限定类名处理,不存在就会抛出下面的异常value = (Class<T>) Resources.classForName(string);}// 返回结果Class对象return value;} catch (ClassNotFoundException e) {throw new TypeException("Could not resolve type alias '" + string + "'.  Cause: " + e, e);}}

Mybatis默认的别名配置

Mybatis 在初始化Configuration对象的时候自身配置了一些Java类型的类型别名。如下所示:

这是Configuration类中TypeAliasRegistry成员初始化创建对象时候进行的配置

// TypeAliasRegistry类构造器初始化public TypeAliasRegistry() {registerAlias("string", String.class);registerAlias("byte", Byte.class);registerAlias("char", Character.class);registerAlias("character", Character.class);registerAlias("long", Long.class);registerAlias("short", Short.class);registerAlias("int", Integer.class);registerAlias("integer", Integer.class);registerAlias("double", Double.class);registerAlias("float", Float.class);registerAlias("boolean", Boolean.class);registerAlias("byte[]", Byte[].class);registerAlias("char[]", Character[].class);registerAlias("character[]", Character[].class);registerAlias("long[]", Long[].class);registerAlias("short[]", Short[].class);registerAlias("int[]", Integer[].class);registerAlias("integer[]", Integer[].class);registerAlias("double[]", Double[].class);registerAlias("float[]", Float[].class);registerAlias("boolean[]", Boolean[].class);registerAlias("_byte", byte.class);registerAlias("_char", char.class);registerAlias("_character", char.class);registerAlias("_long", long.class);registerAlias("_short", short.class);registerAlias("_int", int.class);registerAlias("_integer", int.class);registerAlias("_double", double.class);registerAlias("_float", float.class);registerAlias("_boolean", boolean.class);registerAlias("_byte[]", byte[].class);registerAlias("_char[]", char[].class);registerAlias("_character[]", char[].class);registerAlias("_long[]", long[].class);registerAlias("_short[]", short[].class);registerAlias("_int[]", int[].class);registerAlias("_integer[]", int[].class);registerAlias("_double[]", double[].class);registerAlias("_float[]", float[].class);registerAlias("_boolean[]", boolean[].class);registerAlias("date", Date.class);registerAlias("decimal", BigDecimal.class);registerAlias("bigdecimal", BigDecimal.class);registerAlias("biginteger", BigInteger.class);registerAlias("object", Object.class);registerAlias("date[]", Date[].class);registerAlias("decimal[]", BigDecimal[].class);registerAlias("bigdecimal[]", BigDecimal[].class);registerAlias("biginteger[]", BigInteger[].class);registerAlias("object[]", Object[].class);registerAlias("map", Map.class);registerAlias("hashmap", HashMap.class);registerAlias("list", List.class);registerAlias("arraylist", ArrayList.class);registerAlias("collection", Collection.class);registerAlias("iterator", Iterator.class);registerAlias("ResultSet", ResultSet.class);}

这是Configuration对象创建时候的别名配置

  public Configuration() {typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);typeAliasRegistry.registerAlias("FIFO", FifoCache.class);typeAliasRegistry.registerAlias("LRU", LruCache.class);typeAliasRegistry.registerAlias("SOFT", SoftCache.class);typeAliasRegistry.registerAlias("WEAK", WeakCache.class);typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class);typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class);typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class);}

这些都是Mybatis框架会配置好的,你可以直接使用。

四、总结

TypeAliasRegistry 类完成的别名机制,总的来说源码还是比较简单的,一个Map对象封装起来的就完成了。解析核心配置文件扩大别名使用,有懒就偷。

相关文章:

【Mybatis源码分析】TypeAliasRegistry源码分析

TypeAliasRegistry源码分析一、引入类型别名二、typeAlias 的三种配置方式三、TypeAliasRegistry源码分析三种配置方式源码解析校验过程Mybatis默认的别名配置四、总结一、引入类型别名 当配置 XML 文件&#xff0c;需要指明Java类型时&#xff0c;类型别名可替代Java类型的全…...

节点高负载

如何判断节点高负载? 可以通过 top 或 uptime 来确定 load 大小,如果 load 小于 CPU 数量,属于低负载,如果大于 CPU 数量 2~3 倍,就比较高了,当然也看业务敏感程度,不太敏感的大于 4 倍算高负载。 排查思路 观察监控:通常不是因为内核 bug 导致的高负载,在卡死之前…...

动态规划(一) part1

T1:一个数组 中的最长 升序 子序列 的长度 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组…...

Ubuntu显卡报错:Failed to initialize NVML Driver/library version mismatch

问题描述 输入指令nvidia-smi的时候&#xff0c;出现如下&#xff1a; Failed to initialize NVML: Driver/library version mismatch看起来好像是版本不匹配&#xff0c;在网上查了很多都没有解决问题&#xff0c;重启也不行&#xff0c;结果证明最好的办法是重新安装cuda。…...

JAVA企业电子采购系统源码:采购过程更规范,更透明

满足采购业务全程数字化&#xff0c; 实现供应商管理、采购需求、全网寻源、全网比价、电子招 投标、合同订单执行的全过程管理。 电子招标采购&#xff0c;是指在网上寻源和采购产品和服务的过程。对于企业和企业主来说&#xff0c;这是个既省钱又能提高供应链效率的有效方法…...

5.5G产业再提速!高通5GAdvanced-ready芯片商用终端下半年面世

MWC2023大会召开在即&#xff0c;5GAdvanced产业再添重磅消息&#xff01;2月15日&#xff0c;高通宣布推出全球首个5GAdvanced-ready基带芯片——骁龙X755G调制解调器及射频系统&#xff0c;支持毫米波和Sub-6GHz频段&#xff0c;带来网络覆盖、时延、能效和移动性等全方位的提…...

基于B站王阿华的视频——为什么当下自媒体都在制造焦虑以及如何摆脱

观后笔记2.0——一些深入的思考 1.情绪大约在两千万年前&#xff0c;哺乳脑统治期间诞生。 2.情绪分为积极情绪和负面情绪。决定某种情绪的出现取决于安全感等级。 自媒体制造负面情绪&#xff0c;想尽办法挑起情绪&#xff0c;吸引流量 安全感充足时&#xff0c;由积极情绪…...

一、Docker介绍:

Docker官方网站&#xff1a;https://www.docker.com/ Docker容器技术是虚拟化技术的一个分支&#xff0c;虚拟化技术一般分为两种&#xff1a; 硬件级虚拟化&#xff08;hardware-level-virtualization&#xff09; &#xff1a;是运行在硬件之上的虚拟化技术&#xff0c;它的核…...

Vue进阶(一篇进入Vue3的世界)

文章目录一、初识Vue3二、Vue3新语法糖setup三、响应式数据函数3.1 ref函数3.2 reactive函数3.3 ref和reactive函数的异同四、Vue3的响应式原理五、语法更新5.1 Vue3使用computed计算属性5.2 Vue3使用watch监视属性的注意点5.2.1 监视ref对象5.2.2 监视reactive对象5.2.3 监视嵌…...

功能测试的分类,分别有什么作用?

目录 前言 一、链接测试 二、表单测试 三、搜索测试 四、删除测试 五、cookies/session测试 六、数据库测试 七、峰值测试/容量测试 八、相容性测试/安全测试 前言 功能测试主要包括链接测试、表单测试、搜索测试、删除测试、cookies、session测试、数据库测试等部分…...

51单片机学习笔记_14 红外遥控

红外传感器 遥控器通过红外 LED 发送调制后的信号&#xff0c;开发板上的红外接收模块接收遥控器的红外线。 单工异步&#xff0c;940nm 波长&#xff08;还有一种 250nm 的N&#xff0c;可见光&#xff09;&#xff0c;EC 通信标准。 38KHz&#xff1a;红外线频率。 IN&…...

【我是土堆 - Pytorch教程】 知识点 学习总结笔记(五)

此文章为【我是土堆 - Pytorch教程】 知识点 学习总结笔记&#xff08;五&#xff09;包括&#xff1a;完整的模型训练套路&#xff08;一&#xff09;、完整的模型训练套路&#xff08;二&#xff09;、完整的模型训练套路&#xff08;三&#xff09;、利用GPU训练&#xff08…...

JUC篇:CopyOnWriteArrayList的应用与原理

系列文章目录 JUC篇&#xff1a;volatile可见性的实现原理 JUC篇&#xff1a;synchronized的应用和实现原理 JUC篇&#xff1a;用Java实现一个简单的线程池 JUC篇&#xff1a;java中的线程池 JUC篇&#xff1a;ThreadLocal的应用与原理 JUC篇&#xff1a;Java中的并发工具类 文…...

【总结】爬虫1-requests

爬虫1-requests 1. requests的基本用法 requests需要提前导入&#xff0c;才能使用 1.1 请求网络数据&#xff1a;requests.get(请求地址) response requests.get(https://cd.zu.ke.com/zufang)1.2 设置解码方法&#xff08;罗马的是需要设置 - 一定要在获取请求结果之前设…...

基于springboot实现学生综合成绩测评系统【源码】分享

基于springboot实现学生综合成绩测评系统演示开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包…...

uniapp初体验———uView组件库的使用与钉钉小程序的运行

这周学长给了我一个校企合作的项目&#xff0c;要求是用uniapp开发&#xff0c;最终打包成钉钉小程序&#xff0c;不过我并不会uniapp&#xff0c;也是学了一段时间&#xff0c;开始写项目&#xff0c;中间也遇到过很多问题&#xff0c;比如开发者工具还有如何运行到开发者工具…...

初始Go语言2【标识符与关键字,操作符与表达式,变量、常量、字面量,变量作用域,注释与godoc】

文章目录Go语言基础语法标识符与关键字操作符与表达式变量、常量、字面量变量类型变量声明变量初始化常量字面量变量作用域注释与godoc注释的形式注释的位置go docgodocGo语言基础语法 标识符与关键字 go变量、常量、自定义类型、包、函数的命名方式必须遵循以下规则&#xff…...

Vue计算属性详解

目录 ​编辑 1、什么是计算属性 2、为什么要有计算属性 1. 为什么不是使用模板语法 2. 为什么不是使用method对于复杂逻辑 3. 什么时候要用计算属性 4. 定义计算属性fullName 5. 计算属性的配置项 1、什么是计算属性 写在computed对象中的属性&#xff0c;本质上是…...

rk3568-AD按键驱动调试

rk3568-AD按键驱动调试转载请备注&#xff1a;daisy.skye的博客_CSDN博客-Qt,嵌入式,Linux领域博主dts设备树节点 /rk356x_linux_220118/kernel/arch/arm64/boot/dts/rockchip/rk3568.dtsi 板级设备树dts /home/scooper/jkD7/20221221/ido_evb3568_v2_android11_sdk/kernel/…...

Docker三剑客之swarm

一、什么是docker swarm Swarm是Docker公司推出的用来管理docker集群的平台&#xff0c;几乎全部用GO语言来完成的开发的&#xff0c;代码开源在https://github.com/docker/swarm&#xff0c; 它是将一群Docker宿主机变成一个单一的虚拟主机&#xff0c;Swarm使用标准的Docker…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录

ASP.NET Core 是一个跨平台的开源框架&#xff0c;用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录&#xff0c;以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

初探Service服务发现机制

1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能&#xff1a;服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源&#xf…...

基于PHP的连锁酒店管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...

LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》

&#x1f9e0; LangChain 中 TextSplitter 的使用详解&#xff1a;从基础到进阶&#xff08;附代码&#xff09; 一、前言 在处理大规模文本数据时&#xff0c;特别是在构建知识库或进行大模型训练与推理时&#xff0c;文本切分&#xff08;Text Splitting&#xff09; 是一个…...