mybatis源码解读(7)

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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值