一、背景介紹
??MyBatis作為一個ORM框架诵棵,一個核心的功能是數(shù)據(jù)庫數(shù)據(jù)和Java POJO(即Java Bean)之間的轉(zhuǎn)換,MyBatis是基于JDBC封裝的,先來看一段簡單的JDBC代碼嚣潜。
public Role getRole(Long id) {
Connection connection = getConnection();
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = connection.prepareStatement("select id, role_name, note from t_role where id = ?");
ps.setLong(1, id);
rs = ps.executeQuery();
while (rs.next()) {
Long roleId = rs.getLong("id");
String roleName = rs.getString("role_name");
String note = rs.getString("note");
Role role = new Role();
role.setId(id);
role.setRoleName(roleName);
role.setNote(note);
return role;
}
} catch (Exception e) {
Logger.getLogger(JdbcExample.class.getName()).log(Level.SEVERE, null, e);
} finally {
this.close(rs, ps, connection);
}
return null;
}
??從上面代碼可以看到JDBC執(zhí)行一條帶參數(shù)的SQL時,要有傳入的參數(shù)值id
椅贱,還要知道參數(shù)值的類型Long
懂算,這樣才知道要調(diào)用PreparedStatement
對象的setLong
方法。MyBatis執(zhí)行SQL時庇麦,一般傳入的參數(shù)類型是一個Java Bean计技,設(shè)置SQL參數(shù)往往是用到Java Bean的部分成員屬性,獲取參數(shù)值通過屬性的getter
方法獲取山橄,屬性類型需要通過反射獲取垮媒,一般簡單使用的Java Bean的屬性是跟數(shù)據(jù)庫數(shù)據(jù)表的字段對應(yīng)的,eg:
public class Role {
private long id;
private String roleName;
private String note;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
??當(dāng)然航棱,在更加復(fù)雜的業(yè)務(wù)模型中睡雇,POJO和表結(jié)構(gòu)不是簡單的一對一關(guān)系,可能一個POJO組合在另一個POJO中饮醇,常見于表關(guān)聯(lián)產(chǎn)生的一對一它抱、一對多映射中。POJO成員屬性的數(shù)據(jù)類型雖然常見是基本類型的包裝類(不建議直接使用基本類型如
int
朴艰、long
观蓄,而是使用它們的包裝類Integer
、Long
祠墅,因?yàn)榛绢愋蜁心J(rèn)值侮穿,而包裝類型是對象默認(rèn)為null),但也有可能是集合類型如List
(比如一對多一個訂單下有多個商品)毁嗦,還可能是Map
(當(dāng)然Map
更多用在傳參而不是成員屬性類型或者POJO類型這種語義不強(qiáng)的場景)亲茅。
??如果業(yè)務(wù)模型注重建模,POJO可能還會有繼承關(guān)系,繼承意味子類也繼承了父類的屬性芯急,還有更復(fù)雜的情況勺届,為了靈活使用,一些父類中的屬性類型可能會被設(shè)計(jì)成泛型娶耍,形式可能為<T>
(普通泛型)免姿、<T extends Xxx>
、<T super Yyy>
(限制泛型)榕酒、<? extends Xxx>
胚膊、<? super Yyy>
(通配符泛型),這些都增加了POJO和數(shù)據(jù)表數(shù)據(jù)轉(zhuǎn)換的難度想鹰,因?yàn)閳?zhí)行SQL設(shè)置參數(shù)紊婉、SQL執(zhí)行結(jié)果映射轉(zhuǎn)化為Java對象,都需要知道實(shí)際使用時屬性的確切類型辑舷,還有調(diào)用相應(yīng)屬性的setter
喻犁、getter
,這些都需要依賴Java的反射API來實(shí)現(xiàn)何缓。
Java反射API雖然功能強(qiáng)大肢础,但編寫出高質(zhì)量的反射代碼難度較高,比較復(fù)雜且容易出錯碌廓,為了簡化反射操作的相關(guān)代碼传轰,MyBatis提供了專門的反射模塊,該模塊對 Java 原生的反射進(jìn)行了良好的封裝谷婆,提了更加簡潔易用的 API慨蛙,方便上層使調(diào)用,并且對反射操作進(jìn)行了一系列優(yōu)化纪挎,比如將類的元信息封裝緩存在
MetaClass
對象中期贫,提高了反射操作的性能。
??反射模塊的代碼一覽如下:
二廷区、功能概述
??根據(jù)上面的背景介紹和需求分析總結(jié)唯灵,反射器模塊需要實(shí)現(xiàn)的功能有:
- 1、獲取類的元信息隙轻,包括:構(gòu)造方法埠帕、可讀/可寫的所有屬性、屬性對應(yīng)的
getter/setter
方法 - 2玖绿、根據(jù)類元信息創(chuàng)建Java對象敛瓷,主要是在執(zhí)行完SQL將數(shù)據(jù)轉(zhuǎn)化為Java對象時用到
??關(guān)于相關(guān)組件介紹的系列文章如下:
- [MyBatis源碼分析 - 反射器模塊 - 組件一] Reflector
- [MyBatis源碼分析 - 反射器模塊 - 組件二] Invoker
- [MyBatis源碼分析 - 反射器模塊 - 組件三] ObjectFactory
- [[MyBatis源碼分析 - 反射器模塊 - 組件四] TypeParameterResolver]
- [MyBatis源碼分析 - 反射器模塊 - 組件五] Property 工具集
- [MyBatis源碼分析 - 反射器模塊 - 組件六] MetaClass
- [MyBatis源碼分析 - 反射器模塊 - 組件七] ObjectWrapper
- [MyBatis源碼分析 - 反射器模塊 - 組件八] MetaObject
三、Reflector
??Reflector
是整個反射器模塊的基礎(chǔ)斑匪,通過其解析類的元信息并緩存起來呐籽,源碼解析詳見:[MyBatis源碼分析 - 反射器模塊 - 組件一] Reflector。
四、Invoker
??Invoker
是一個接口狡蝶,緩存了類屬性對應(yīng)的 Field 對象和 getter/setter 方法對應(yīng)的 Method 對象庶橱,設(shè)置獲取屬性值、調(diào)用方法贪惹,實(shí)際上是調(diào)用 Field 對象和 Method 對象的反射方法去完成苏章,Reflector
中的 getMethods
、setMethods
屬性緩存了屬性和對應(yīng)的 Invoker 對象的映射奏瞬,源碼解析詳見:[MyBatis源碼分析 - 反射器模塊 - 組件二] Invoker枫绅。
五、ObjectFactory
??ObjectFactory
從名字上看很容器猜出用途硼端,對象工廠就是用來創(chuàng)建對象的并淋,MyBatis 中會使用該類來創(chuàng)建所有需要的新對象,源碼解析詳見:[MyBatis源碼分析 - 反射器模塊 - 組件三] ObjectFactory珍昨。
六县耽、TypeParameterResolver
??TypeParameterResolver
是一個類型參數(shù)解析器,即JavaBean中可能帶泛型如 List<T>曼尊、通配符如 <? super SubClass>酬诀,而且可能復(fù)雜的繼承關(guān)系脏嚷,為了獲取到運(yùn)行時正確具體的類型(包括屬性類型骆撇、方法參數(shù)類型、方法返回值類型)父叙,需要使用該類解析類型參數(shù)神郊,源碼解析詳見:[[MyBatis源碼分析 - 反射器模塊 - 組件四] TypeParameterResolver]。
七趾唱、Property 工具集
??主要有三個工具類:PropertyCopier
涌乳、PropertyNamer
、PropertyTokenizer
甜癞。分別用來拷貝對象屬性值夕晓、從方法名提取屬性信息、解析屬性表達(dá)式悠咱,源碼解析詳見:[MyBatis源碼分析 - 反射器模塊 - 組件五] Property 工具集蒸辆。
八、MetaClass
??MetaClass
通過對 Reflector
和 PropertyTokenizer
組合使用析既,實(shí)現(xiàn)了對復(fù)雜的屬性表達(dá)式的解析躬贡,并實(shí)現(xiàn)了獲取指定屬性描述信息的功能,源碼解析詳見:[MyBatis源碼分析 - 反射器模塊 - 組件六] MetaClass眼坏。
九拂玻、ObjectWrapper
??ObjectWrapper
接口是對對象的包裝,抽象了對象的屬性信息,它定義了一系列查詢對象屬性信息檐蚜、以及更新屬性的方法魄懂,源碼解析詳見:[MyBatis源碼分析 - 反射器模塊 - 組件七] ObjectWrapper。
十闯第、MetaObject
??MetaObject
封裝了 ObjectWrapper 對象和相應(yīng)配套的工廠對象逢渔,主要聯(lián)合實(shí)現(xiàn)對表達(dá)式的解析和配套的操作,形成一組完成的操作對象的方法乡括,其源碼解析詳見:[MyBatis源碼分析 - 反射器模塊 - 組件八] MetaObject肃廓。