在我們平時寫sql時為了簡化書寫,方便理解記憶會經常用到別名,比如一個表名很長可以直接取別名a就可以代替,還有比如你查詢出來的結果有的字段很長不是通俗叫法,我們可以取你想要的字段名。別名的好處是顯而易見的,mybatis把這個好處也擴展到了類上。
官網(http://mybatis.github.io/mybatis-3/configuration.html#typeAliases)有雲:
A type alias is simply a shorter name for a Java type. It's only relevant to the XML configuration and simply exists to reduce redundant typing of fully qualified classnames.
別名類型只是一個java類型的縮寫名。它只和XML配置文件相關,它存在的目的是為了減少全路徑類名的輸入。在mybatis的配置文件中有兩種定義方式:
<typeAliases>
<!-- 指定一個具體的類的別名 -->
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<!-- 指定一個包中所有類的別名,后面會講到mybatis是如何注冊這個包里的類 -->
<package name="domain.blog"/>
</typeAliases>
從官網上可以看到,mybatis對常用的java類型都內建了別名。
言歸正傳,我們開始看看mybatis是如何實現別名功能的,這回涉及到一個類和一個注解。
一、TypeAliasRegistry
TypeAliasRegistry類位於org.apache.ibatis.type包(關於這個包更多的介紹可以參考 http://www.cnblogs.com/sunzhenchao/archive/2013/04/09/3009431.html),別名相關的功能都在類中完成,我們先看看這個類包含的屬性:
private final HashMap<String, Class> TYPE_ALIASES = new HashMap<String, Class>();
這個map的key類型是String,value類型是Class。key就是這個類的別名。
在了解完這個類的屬性之后,我們再了解下mybatis是如何注冊別名的。
1、注冊一個類的別名
我們先看如何將一個類的別名注冊到mybatis中的,即如何解析mybatis配置文件中的
<typeAlias alias="Author" type="domain.blog.Author"/>
這個文本元素。
public void registerAlias(String alias, Class value) { assert alias != null; // 把別名轉為小寫字母 String key = alias.toLowerCase(); // 如果key或者alias如果已經添加到了map中,且對應的class和已添加的不一致則拋出異常 if (TYPE_ALIASES.containsKey(key) && !TYPE_ALIASES.get(key).equals(value.getName()) && TYPE_ALIASES.get(alias) != null) { if (!value.equals(TYPE_ALIASES.get(alias))) { throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(alias).getName() + "'."); } } // 否則添加到map中 TYPE_ALIASES.put(key, value); }
2、注冊一個包中所有類的別名
首先需要把這個包中所有的類都找到,然后再進行注冊。將這個包所有的類都讀到內存中用到的函數為:
public void registerAliases(String packageName){ // 第二個會在mybatis的io去尋找對應的類時會用到 // 因為是把這個包中所有的類都進行別名注冊,因而用的的Object類 registerAliases(packageName, Object.class); } public void registerAliases(String packageName, Class superType){ ResolverUtil<Class> resolverUtil = new ResolverUtil<Class>(); // mybatis的io去包中尋找對應的類,因為是把這個包中所有的類都進行別名注冊 // 因而此時會將所有的類都讀到 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) // 忽略內部類和接口 if (!type.isAnonymousClass() && !type.isInterface()) { registerAlias(type); } } }
前面是讀到所有的類,現在開始進行注冊:
public void registerAlias(Class type) { // 利用反射機制得到這個類的不包含包名的簡單名稱 String alias = type.getSimpleName(); // 如果這個類有Alias這個注解,獲取這個注解的值作為別名,否則就用自己的原始類名 Alias aliasAnnotation = (Alias) type.getAnnotation(Alias.class); if (aliasAnnotation != null) { alias = aliasAnnotation.value(); } // 開始注冊,這個步驟在上一小節有講,不再進行重復 registerAlias(alias, type); }
二、別名功能初始化
前面提到mybatis中已經對許多常用的java對象內建了別名,那么這些別名是什么時候又是如何加載到mybatis中呢?
我們還要回到mybatis的Configuration類,這個類包含了mybatis的各種各樣的配置,別名的配置也在其中,Configuration類包含了一個屬性:
protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
而在TypeAliasRegistry類的構造函數中會為常用的java對象內建別名,詳細情況可直接看源代碼。