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了。