Mybatis中TypeAliasRegistry的作用及使用方法

 更新时间:2023年05月08日 09:21:21   作者:假正经的小柴  
Mybatis中的TypeAliasRegistry是一个类型别名注册表,它的作用是为Java类型建立别名,使得在Mybatis配置文件中可以使用别名来代替完整的Java类型名。使用TypeAliasRegistry可以简化Mybatis配置文件的编写,提高配置文件的可读性和可维护性

一、引入类型别名

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

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

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

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

<typeAliases>
<! --<package name="com.ncpowernode .mybatis.bean" />-->
<typeAlias type="com.ncpowernode .mybatis.bean. User"/>
</typeAliases>

即可写成下面的形式:

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

二、typeAlias的三种配置方式

type属性和alias属性双搭

<typeAlias type="com.ncpowernode.mybatis.bean.User" alias="user"/>

直接写type属性指定全限定类名,底层会利用该类的simpleName去当作这个alias。

<typeAlias type="com.ncpowernode.mybatis.bean.User"/>

直接配置包标签,使得指定包下的所有类都进行别名配置。

<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);
      }
    }
  }

校验过程

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

  • 为什么使用别名的时候各个字符不区分大小写;
  • 为什么使用别名也行,使用全限定类名也行。
  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的作用及使用方法的文章就介绍到这了,更多相关Mybatis TypeAliasRegistry内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Springboot使用Spring Data JPA实现数据库操作

    Springboot使用Spring Data JPA实现数据库操作

    Spring Data JPA 是 Spring 基于 Spring Data 框架、在JPA 规范的基础上开发的一个框架,使用 Spring Data JPA 可以极大地简化JPA 的写法,本章我们将详细介绍在Springboot中使用 Spring Data JPA 来实现对数据库的操作
    2021-06-06
  • SpringMVC和Ajax的交互详解(手工处理)

    SpringMVC和Ajax的交互详解(手工处理)

    Ajax即异步的 JavaScript和XML,是一种无需重新加载整个网页的情况下,能够更新部分模块的网页技术,下面这篇文章主要给大家介绍了关于SpringMVC和Ajax交互的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-08-08
  • Java tomcat环境变量及idea配置解析

    Java tomcat环境变量及idea配置解析

    这篇文章主要介绍了Java tomcat环境变量及idea配置解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-12-12
  • java实现自动售货机

    java实现自动售货机

    这篇文章主要为大家详细介绍了java实现自动售货机,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • 再也不用怕! 让你彻底搞明白Java内存分布

    再也不用怕! 让你彻底搞明白Java内存分布

    做Java的大都没有c++ 的那种分配内存的烦恼,因为Java 帮我们管理内存,但是这并不代表我们不需要了解Java的内存结构,因为线上经常出现内存的问题,今天聊一下内存的问题,需要的朋友可以参考下
    2021-06-06
  • mybatisplus使用xml的示例详解

    mybatisplus使用xml的示例详解

    这篇文章主要介绍了mybatisplus使用xml,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08
  • SpringBoot自定义注解之实现AOP切面日志详解

    SpringBoot自定义注解之实现AOP切面日志详解

    这篇文章主要为大家详细介绍了SpringBoot自定义注解之实现AOP切面统一打印出入参日志,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-09-09
  • JDK 14的新特性:文本块Text Blocks的使用

    JDK 14的新特性:文本块Text Blocks的使用

    这篇文章主要介绍了JDK 14的新特性:文本块Text Blocks的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • Java实现分页的几种方法详细解析

    Java实现分页的几种方法详细解析

    这篇文章主要介绍了Java实现分页的几种方法详细解析,在Java中想实现分页功能有几种常用的方法,今天我们就来详细解析一下,文中提供了解决思路和部分实现代码,需要的朋友可以参考下
    2023-11-11
  • IntelliJ IDEA多屏后窗口不显示问题解决方案

    IntelliJ IDEA多屏后窗口不显示问题解决方案

    这篇文章主要介绍了IntelliJ IDEA多屏后窗口不显示问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09

最新评论