简述
typeAlias即类型别名,我们在使用mybatis时经常会设置并使用这一功能,如在编写XML映射SQL语句中的parameterType,resultType属性时,我们会直接使用String,而不是java.lang.String,帮助我们完成这一简化过程的就是TypeAliasRegistry类。
源码分析
与之前文章TypeHandlerRegistry源码简单分析类似,TypeAliasRegistry也是使用一个Map(这里是HashMap)去维护别名与真实类的对应关系
private final Map<String, Class<?>> TYPE_ALIASES = new HashMap<String, Class<?>>();
TypeAliasRegistry在初始化时,便在无参构造函数中帮我们完成了一些基础别名的映射实现,源码如下
public TypeAliasRegistry() {
//字符串类型
registerAlias("string", String.class);
//基本包装类型
registerAlias("byte", Byte.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("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("_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("_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);
//mybatis中的resultSet
registerAlias("ResultSet", ResultSet.class);
}
TypeAliasRegistry提供了三种registerAlias的实现,源码如下
【最核心的方法】
//逻辑清晰明了
public void registerAlias(String alias, Class<?> value) {
if (alias == null) {
throw new TypeException("The parameter alias cannot be null");
}
// issue #748
//别名统一转换为小写去比较
String key = alias.toLowerCase(Locale.ENGLISH);
if (TYPE_ALIASES.containsKey(key) && TYPE_ALIASES.get(key) != null && !TYPE_ALIASES.get(key).equals(value)) {
//如果map中存在该k,v,则抛出对应异常
throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(key).getName() + "'.");
}
//否则存入map(key存在覆盖,不存在新增)
TYPE_ALIASES.put(key, value);
}
其它的registerAlias主要是方便用户去自定义别名,最终都会指向核心方法
【包扫描】
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){
// Ignore inner classes and interfaces (including package-info.java)
// Skip also inner classes. See issue #6
if (!type.isAnonymousClass() && !type.isInterface() && !type.isMemberClass()) {
//对包路径下的类进行循环注册
registerAlias(type);//指向【类型扫描】
}
}
}
对应我们常用的包扫描注册方式
<typeAliases>
<package name="com.xx.xx.xx"/>
</typeAliases>
【类型扫描】
参数只有一个Class<?> type,默认别名为该类的首字母小写,然后会判断该类是否被@Alias注解修饰并指定别名,如果有则使用该别名,没有的话就还是首字母小写,然后指向核心方法进行注册
public void registerAlias(Class<?> type) {
String alias = type.getSimpleName();
Alias aliasAnnotation = type.getAnnotation(Alias.class);
if (aliasAnnotation != null) {
alias = aliasAnnotation.value();
}
registerAlias(alias, type);
}
对应【类型】注册方式
<typeAliases>
<typeAlias type="com.xxx.xx.User"/>
</typeAliases>
【类型,类全名扫描】
通过反射将类全名解析为Class类,然后指向核心方法
public void registerAlias(String alias, String value) {
try {
registerAlias(alias, Resources.classForName(value));
} catch (ClassNotFoundException e) {
throw new TypeException("Error registering type alias "+alias+" for "+value+". Cause: " + e, e);
}
}
对应【类型,类全名】注册方式
<typeAliases>
<typeAlias type="com.xxx.xx.User" alias="user" />
</typeAliases>
【别名解析】
当我们使用别名时,通过TypeAliasRegistry的resolveAlias进行解析得到实际的类
public <T> Class<T> resolveAlias(String string) {
try {
if (string == null) {
return null;
}
// issue #748
//mybatis默认的别名均为小写,但是写成大写也无妨,因为解析时通通转化为小写
String key = string.toLowerCase(Locale.ENGLISH);
Class<T> value;
if (TYPE_ALIASES.containsKey(key)) {
//map中存在对应key、value则取出value
value = (Class<T>) TYPE_ALIASES.get(key);
} else {
//不存在则直接通过反射获取Class,即我们在使用时可以直接写全名
value = (Class<T>) Resources.classForName(string);
}
return value;
} catch (ClassNotFoundException e) {
throw new TypeException("Could not resolve type alias '" + string + "'. Cause: " + e, e);
}
}
除了TypeAliasRegistry自带的别名映射外,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);
}