【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对象封装起来的就完成了。解析核心配置文件扩大别名使用,有懒就偷。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

几种常见的校验算法

目录 一、校验和 二、异或校验 三、CRC校验 四、MD5算法 五、SM3算法 六、SHA算法 UART有一个奇偶校验&#xff0c;CAN通信有CRC校验。Modbus、USB等通信协议也有校验信息。在自定义数据存储时&#xff0c;有经验的工程师一般都会添加一定校验信息。 一、校验和 校验和…

Maven项目导入本地依赖

今天在打包一个javafx项目时&#xff0c;因为有一个jar包在mvn本地仓库和网上仓库都没有&#xff0c;所以打包后程序功能不完整&#xff0c;CSDN上看了一堆&#xff0c;都是介绍了一堆方法但每个方法都不太详细&#xff0c;唉...还是自己来吧 1. 在IDEA内执行mvn install语句将…

【STM32学习】实时时钟 —— RTC

【STM32学习】实时时钟 —— RTC零、参考一、工作原理1、RTC介绍2、工作过程二、相关寄存器三、代码说明1、rtc初始化2、关于中断3、中断配置代码&#xff08;仅供参考&#xff09;3.1 秒中断普通闹钟功能3.2 待机模式唤醒3.3 停机模式唤醒零、参考 STM32RTC实时时钟实验讲解&…

复杂度和简单排序算法【左程云:Java】

目录 1.常见的常数时间操作 2.选择排序 3.冒泡排序 ​编辑 4.位运算----异或运算【相同为0&#xff0c;不同为1无进位相加】 ​编辑 异或的性质 使用异或前的条件&#xff1a;【a&#xff0c;b在内存独立】 异或&#xff1a;可以用于交换两个变量的值 练习1&#xff1a; …

MySQL-用户与权限

目录 &#x1f341;DB权限表 &#x1f341;新建普通用户 &#x1f342;创建新用户(create user) &#x1f342;创建新用户(grant) &#x1f341;删除普通用户 &#x1f341;修改用户密码 &#x1f342;Root用户修改自己的密码 &#x1f342;Root用户修改普通用户密码 &#x1f…

新手学SpringCloud前需知道的5点

目录 第一点&#xff1a; 什么是微服务架构 第二点&#xff1a;为什么需要学习Spring Cloud 第三点&#xff1a; Spring Cloud 是什么 第四点&#xff1a; SpringCloud的优缺点 1、SpringCloud优点 2、SpringCloud缺点 第五点&#xff1a; SpringCloud由什么组成 1&…

现代卷积神经网络(GoogleNet),并使用GoogleNet进行实战CIFAR10分类

专栏&#xff1a;神经网络复现目录 本章介绍的是现代神经网络的结构和复现&#xff0c;包括深度卷积神经网络&#xff08;AlexNet&#xff09;&#xff0c;VGG&#xff0c;NiN&#xff0c;GoogleNet&#xff0c;残差网络&#xff08;ResNet&#xff09;&#xff0c;稠密连接网络…

react插槽和HOC高阶组件

react组件插槽写法方式&#xff1a;<Table>内容</Table> //react插槽在自定义组件的内容位置。使用插槽完成&#xff1a;封装简单组件&#xff1a;在内容区域使用插槽 <Tab num{11} content"待收费数据&#xff08;条&#xff09;"><i classNam…

【SSM】SpringMVC中的@RequestMapping注解(含源码解析)

RequestMapping注解推荐文献Request Mapping源码分析&#xff0c;探索这些子注解的作用RequestMapping注解的位置Ant 风格的路径匹配推荐文献 一文掌握RequestMapping注解 SpringMVC请求参数和路径变量 SpringMVC官方文档 路径匹配工具&#xff08;AntPathMatcher vs PathP…

WireShark如何抓包,各种协议(HTTP、ARP、ICMP)的过滤或分析,用WireShark实现TCP三次握手和四次挥手

WireShark一、开启WireShark的大门二、如何抓包 搜索关键字2.1 协议过滤2.2 IP过滤2.3 过滤端口2.4 过滤MAC地址2.5 过滤包长度2.6 HTTP模式过滤三、ARP协议分析四、WireShark之ICMP协议五、TCP三次握手与四次挥手5.1 TCP三次握手实验5.2 可视化看TCP三次握手5.3 TCP四次挥手5.…

各种硬件对应”位数“,各种字长,编址方式的区分。

这里写目录标题1.编址方式①存储元&#xff0c;存储单元&#xff0c;存储体/存储矩阵&#xff0c;存储器/存储系统。②按字编址和按字节编址2.各种易混淆的"长度概念"①字&#xff0c;字长/机器字长&#xff0c;指令字长&#xff0c;存储字长。3.常见硬件对应位数及原…

软文写作技巧有哪些?建议收藏

世上无难事&#xff0c;只是很多时候我们并没有掌握其中的技巧罢了&#xff0c;软文写作亦是如此&#xff0c;一定要掌握好其中的门道&#xff0c;才能让我们的写作变得更加顺畅。 接下来伯乐网络传媒就来给大家分享这几个超实用的软文写作技巧&#xff0c;相信一定会对你有所…

基于Java+Springboot+vue的网上商城购物系统设计与实现【源码(完整源码请私聊)+论文+演示视频+包运行成功】

博主介绍&#xff1a;专注于Java技术领域和毕业项目实战 &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 Java项目精品实战案例&#xff08;200套&#xff09; 目录 一、前言介绍 1.…

vue 高德地图添加多个点标记

新建文件 amap.vue&#xff1a; <template><div id"amapcontainer" style"width: 1000px; height: 720px"></div> </template><script> import AMapLoader from amap/amap-jsapi-loader; window._AMapSecurityConfig {sec…

速度与兼容性功能大比拼:7款浏览器测评,哪一款更好用

还在为使用哪款浏览器而发愁吗&#xff1f;电脑配置低&#xff0c;又想浏览网页顺畅、下载速度快&#xff0c;那么就要挑选功能齐全、速度快的浏览器。话不多说&#xff0c;给大家做了7款浏览器的最全测评&#xff0c;看看2023年哪个浏览器更好用&#xff0c;更适合自己。 本次…

基于云计算的Java版云HIS系统源码,已在公立二甲医院应用三年

系统概述&#xff1a; 这是一套SaaS模式Java版云HIS系统源码&#xff0c;已在公立二甲医院应用三年&#xff0c;系统运行稳定、功能齐全&#xff0c;界面布局合理、操作简便。融合B/S版电子病历系统&#xff0c;支持电子病历四级&#xff0c;HIS与电子病历系统均拥有自主知识产…

物理机CPU使用率报警

背景知识 (background) CPU是稀缺的共享资源&#xff0c;CPU使用率过高&#xff0c;可能造成更多的上下文切换、调度延迟、CGroup CPU Throttle。 无论是物理机或容器化混合部署的应用&#xff0c;CPU做不到完全隔离&#xff0c;最多只能限制使用上限。部分进程CPU使用过多&a…

自动指出测试问题,TestGPT来袭,测试工程师,你准备好了么

测试是软件开发流程的关键部分。软件代码引起的错误在2020年给美国本土企业造成了2.08万亿的损失。鉴于如此高昂的成本&#xff0c;预防代码错误成为一件重要的事情&#xff0c;这也是测试这个工作产生的根本原因。为了防止错误&#xff0c;开发需要进行定期和彻底的测试&#…

ShowMeAI周刊 | AI独立开发者:帆船旅行但月入万刀;创业吧!新黄金时代来了;资本看好哪些创业方向;被AI震麻的一周again

这是ShowMeAI周刊的第8期。聚焦AI领域本周热点&#xff0c;及其在各圈层泛起的涟漪&#xff1b;拆解AI独立开发者的盈利案例&#xff0c;关注中美AIGC的创业者们&#xff0c;并提供我们的商业洞察。欢迎关注与订阅&#xff01; | &#x1f440;日报&周刊合辑 ⌛ 『Danielle…

线程基础知识总结

文章目录[toc]1. 认识线程&#xff08;Thread&#xff09;1.1 概念1.2 创建线程1.2.1 方法1 继承Thread类1.2.2 方法2 实现Runnable接口1.2.3 实现 Callable 接口&#xff0c;使用 FutureTask 接收线程返回值1.2.4 对比上面两种方法2. Thread类及常见方法2.1 Thread的常见构造方…
最新文章