Mybatis中TypeAliasRegistry的作用及使用方法
作者:假正经的小柴
一、引入类型别名
当配置 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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!