typeAliasesElement 加载类型别名
解析配置的别名
XMLConfigBuilder.typeAliasesElement(root.evalNode(“typeAliases”));
创建 User
类,用于辅助测试
package com.tky.ibatis.model;
// ......
public class User implements Serializable{
private Long id ;
private Long version ;
private String username ;
private String password ;
private Date createTime ;
// setter and getter
}
首先在 mybatis-config.xml
configuration
节点中加入如下配置
<typeAliases>
<typeAlias type="com.tky.ibatis.model.User" alias="typeAlias_user"/>
<package name="com.tky.ibatis.model"/>
</typeAliases>
- 类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
typeAliases
节点允许添加两种节点(typeAlias,package
),如果同时使用两种方式要求typeAlias
的声明必须在package
之前- 它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。例如:
long
->_long
处理逻辑代码
private void typeAliasesElement(XNode parent) {
if (parent != null) {
// 获取 typeAliases 节点下的子节点进行处理
for (XNode child : parent.getChildren()) {
// 使用package元素指定 将包下的类型全部映射对应的别名简称
if ("package".equals(child.getName())) {
String typeAliasPackage = child.getStringAttribute("name");
typeAliasRegistry.registerAliases(typeAliasPackage);
} else { // 使用typeAlias元素直接指定
String alias = child.getStringAttribute("alias");
String type = child.getStringAttribute("type");
try {
Class<?> clazz = Resources.classForName(type);
if (alias == null) {
typeAliasRegistry.registerAlias(clazz);
} else {
typeAliasRegistry.registerAlias(alias, clazz);
}
} catch (ClassNotFoundException e) {}
}
}
}
}
package
最终解析使用的是 TypeAliasRegistry.registerAliases(String packageName)
方法进行解析,通过ResolverUtil
工具找到指定包路径下的所有class
文件然后注册进系统。
其中匿名内部类、接口和局部成员类是不会被注册的,这些类通常只进行一次使用或者没有具体实现,不适合作为常量注册进系统使用。
typeAlias
则直接使用 TypeAliasRegistry.registerAlias(String alias, String value)
进行注册。
1 使用typeAlias
元素直接指定
public void registerAlias(String alias, Class<?> value) {
String key = alias.toLowerCase(Locale.ENGLISH);
// 对于已经注册过的值不进行覆盖处理
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() + "'.");
}
typeAliases.put(key, value);
}
2 使用package
元素 注册包下所有类型
通过工具类 ResolverUtil
找到该包下的所有的类,然后使用类的名称(SimpleName
)作为别名将类型注册进系统。
public void registerAliases(String packageName) {
registerAliases(packageName, Object.class);
}
public void registerAliases(String packageName, Class<?> superType) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
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 void registerAlias(Class<?> type) {
// 不指定别名时,默认使用类名作为别名
String alias = type.getSimpleName();
Alias aliasAnnotation = type.getAnnotation(Alias.class);
if (aliasAnnotation != null) {
alias = aliasAnnotation.value();
}
registerAlias(alias, type);
}
ResolverUtil
辅助类处理工具
这里有一个有趣的工具类 ResolverUtil
ResolverUtil.find(new ResolverUtil.IsA(superType), packageName)
查找指定包路径下的类,两个参数:第一个指定过滤器,指定要过滤的超类;第二个指明包路径,指明要查找那个包下面的类。
实现代码如下,VFS.getInstance().list(path)
就是MyBatis 源码解读(三)指定VFS 的实现 介绍的配置
public ResolverUtil<T> find(Test test, String packageName) {
String path = packageName == null ? null : packageName.replace('.', '/');
try {
// 可自定义VFS 实例
List<String> children = VFS.getInstance().list(path);
for (String child : children) {
if (child.endsWith(".class")) {
// 将找到的类型添加进集合用于后续处理
addIfMatching(test, child);
}
}
} catch (IOException ioe) {}
return this;
}
// 添加进集合用于后续处理
protected void addIfMatching(Test test, String fqn) {
try {
String externalName = fqn.substring(0, fqn.indexOf('.')).replace('/', '.');
ClassLoader loader = getClassLoader();
Class<?> type = loader.loadClass(externalName);
if (test.matches(type)) {
matches.add((Class<T>) type);
}
} catch (Throwable t) {}
}
编写单元测试,看看运行结果是否和我们预期的一致。
public class TypeAliasesTest extends BaseTest {
@Override
public String getResource() {
return "com/tky/perperties/mybatis-config.xml";
}
@Test
public void testAliases() {
Map<String, Class<?>> types = sqlSessionFactory.getConfiguration().getTypeAliasRegistry().getTypeAliases();
assertEquals(User.class, types.get("typealias_user"));
assertEquals(User.class, types.get("user"));
}
}