Mybatis中alices的实现
mybatis 别名
1.别名的作用
别名是一个指代的名称,当类的全限定名过长的时候,我们可以用一个简短的名称指代它,这个名称可以再全文指代。
2.使用方式
别名的实现方式有三种
(1).指定一个类路径,并指定这个类的别名
<typeAliases> <typeAlias alias="Users" type="com.dzy.mybatis.model.Users"/> </typeAliases>
(2).第二种方式,指定类名和别名
<typeAliases> <typeAlias type="com.dzy.mybatis.model.Card"/> </typeAliases>
(3).指定一个包名,mybatis会自动扫描包下可以使用别名的类
<typeAliases> <package name="com.dzy.mybatis.model" /> </typeAliases>
3.源码分析
<typeAliases>的加载过程
代码入口:typeAliasesElement(root.evalNode("typeAliases"));
typeAlias的加载方式,首先进入<typeAliases>标签后,先判断子节点。
(1).如果子节点是<package>,
调用configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage)方法
(2).如果子节点是<typeAlias>,判断type的内容
如果type为null,调用typeAliasRegistry.registerAlias(clazz);
如果type不为null,调用typeAliasRegistry.registerAlias(alias, clazz)
private void typeAliasesElement(XNode parent) { if (parent != null) { //获取所有的子节点 for (XNode child : parent.getChildren()) { if ("package".equals(child.getName())) { //<package name="" />加载方式 String typeAliasPackage = child.getStringAttribute("name"); configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage); } else { // 获取 alias 和 type 属性值,alias可为空 String alias = child.getStringAttribute("alias"); String type = child.getStringAttribute("type"); try { // 加载 type 对应的类型 Class<?> clazz = Resources.classForName(type); if (alias == null) { //<typeAlias type=""/>加载方式 typeAliasRegistry.registerAlias(clazz); } else { //<typeAlias alias="" type=""/>加载方式 typeAliasRegistry.registerAlias(alias, clazz); } } catch (ClassNotFoundException e) { throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e); } } } } }
分析别名的加载,三种情况
首先分析指定类路径,并指定这个类的别名的加载方式。原因是另外两种方法其实最后还是调用了这个方式
<typeAlias alias="Users" type="com.dzy.mybatis.model.Users"/>
//alias != null
//<typeAlias alias="Users" type="com.dzy.mybatis.model.Users"/>
typeAliasRegistry.registerAlias(alias, clazz);
public void registerAlias(String alias, Class<?> value) { if (alias == null) throw new TypeException("The parameter alias cannot be null"); //将Alias的值大写转换为小写 String key = alias.toLowerCase(Locale.ENGLISH); // issue #748 //TYPE_ALIASES的定义: //private final Map<String, Class<?>> TYPE_ALIASES = new HashMap<String, Class<?>>(); //如果TYPE_ALIASES中存在,抛出异常,否则,放入到TYPE_ALIASES中 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);
}
//alias == null
//<typeAlias type="com.dzy.mybatis.model.Card"/>
typeAliasRegistry.registerAlias(clazz);
//处理思路是通过type获取类名,然后调用registerAlias(alias, type)方法
public void registerAlias(Class<?> type) { //获取全路径类名的简称 String alias = type.getSimpleName(); Alias aliasAnnotation = type.getAnnotation(Alias.class); if (aliasAnnotation != null) { // 从注解中取出别名 alias = aliasAnnotation.value(); } //调用registerAlias方法 registerAlias(alias, type);
}
//<package name="com.dzy.mybatis.model" />
String typeAliasPackage = child.getStringAttribute("name");
configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
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); } }
}