mybatis源码解读(7)

来源:互联网 发布:西门子em235编程 编辑:程序博客网 时间:2024/06/05 16:17

typeAliases别名机制解析

private void typeAliasesElement(XNode parent) {    if (parent != null) {      for (XNode child : parent.getChildren()) {        if ("package".equals(child.getName())) {          String typeAliasPackage = child.getStringAttribute("name");          configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);        } else {          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) {            throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);          }        }      }    }  }
<typeAliases>  <typeAlias alias="Author" type="domain.blog.Author"/>  <typeAlias alias="Blog" type="domain.blog.Blog"/>  <typeAlias alias="Comment" type="domain.blog.Comment"/>  <typeAlias alias="Post" type="domain.blog.Post"/>  <typeAlias alias="Section" type="domain.blog.Section"/>  <typeAlias alias="Tag" type="domain.blog.Tag"/></typeAliases>

或者

<typeAliases>  <package name="domain.blog"/></typeAliases>

文件的解析很简单,循环他的子节点,然后判断节点的类型,是package还是typeAlias,执行相应的逻辑。
我们先来看typeAlias的逻辑。

if (alias == null) {   typeAliasRegistry.registerAlias(clazz);} else {   typeAliasRegistry.registerAlias(alias, clazz);}

这个可以看出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);  }

不传别名的注册:
拿到类的simpleName(即不包含包名的类名)。再去获取该类是否有Alias注解。
这个逻辑可以看出,对于不写别名的类型,如果写了Alias注解,已注解的为准,如果没写注解,就使用类的简单名称(这里原来大写还是大写)。

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); // issue #748    if (TYPE_ALIASES.containsKey(key) && TYPE_ALIASES.get(key) != null && !TYPE_ALIASES.get(key).equals(value)) {      throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(key).getName() + "'.");    }    TYPE_ALIASES.put(key, value);  }

可以看到,这里的别名统一转成了小写,然后放到一个map中。
org.apache.ibatis.type.TypeAliasRegistry#TypeAliasRegistry
查看TypeAliasRegistry的构造方法。

registerAlias("string", String.class);registerAlias("byte", Byte.class);registerAlias("long", Long.class);...

最后我们看下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){      // 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);      }    }  }

这里的逻辑也比较简单,查找包下的类,一一注册成别名就可以了。
这里有特定的是ResolverUtil这个工具类。也不掉大家胃口了,看看他是怎么实现查找包下的类的。
这个类下有个集合,是存放查找结果的

/** The set of matches being accumulated. */  private Set<Class<? extends T>> matches = new HashSet<Class<? extends T>>();

里面的find方法

public ResolverUtil<T> find(Test test, String packageName) {    String path = getPackagePath(packageName);    try {      List<String> children = VFS.getInstance().list(path);      for (String child : children) {        if (child.endsWith(".class"))          addIfMatching(test, child);      }    } catch (IOException ioe) {      log.error("Could not read package: " + packageName, ioe);    }    return this;  }

getPackagePath把包路径的“.”换成“/”,然后用VFS.getInstance().list(path)来获取该路径下的文件,这个查找文件是通过
Collections.list(Thread.currentThread().getContextClassLoader().getResources(path));
来获取的,然后还要经过一次list的转换,这下面就比较复杂了。有兴趣的同学可以继续往下看,我们再深入就没完没了了。

这里注册了很多默认的别名。以上即别名机制的全部内容。其实很简单是不是。看了源码,别名是不是就可以用的很6了。

0 0
原创粉丝点击