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




