基礎(chǔ)支持層位于MyBatis整體架構(gòu)的最底層,支撐著MyBatis的核心處理層,是整個(gè)框架的基石。基礎(chǔ)支持層中封裝了多個(gè)較為通用的、獨(dú)立的模塊。不僅僅為MyBatis提供基礎(chǔ)支撐,也可以在合適的場景中直接復(fù)用。
反射模塊詳解
MyBatis在進(jìn)行參數(shù)處理、結(jié)果集映射等操作時(shí)會(huì)使用到大量的反射操作,JAVA中的反射功能雖然強(qiáng)大,但是代碼編寫起來比較復(fù)雜且容易出錯(cuò),為了簡化反射操作的相關(guān)代碼,MyBatis提供了專門的反射模塊,該模塊位于
org.Apache.ibatis.reflection包下,它對常見的反射操作做了進(jìn)一步的封裝,提供了更加簡潔方便的反射API。
1 Reflector
Reflector是反射模塊的基礎(chǔ),每個(gè)Reflector對象都對應(yīng)一個(gè)類,在Reflector中緩存了反射需要使用的類的元信息
1.1 屬性
? 首先來看下Reflector中提供的相關(guān)屬性的含義
// 對應(yīng)的Class 類型
private final Class<?> type;
// 可讀屬性的名稱集合 可讀屬性就是存在 getter方法的屬性,初始值為null
private final String[] readablePropertyNames;
// 可寫屬性的名稱集合 可寫屬性就是存在 setter方法的屬性,初始值為null
private final String[] writablePropertyNames;
// 記錄了屬性相應(yīng)的setter方法,key是屬性名稱,value是Invoker方法
// 它是對setter方法對應(yīng)Method對象的封裝
private final Map<String, Invoker> setMethods = new HashMap<>();
// 屬性相應(yīng)的getter方法
private final Map<String, Invoker> getMethods = new HashMap<>();
// 記錄了相應(yīng)setter方法的參數(shù)類型,key是屬性名稱 value是setter方法的參數(shù)類型
private final Map<String, Class<?>> setTypes = new HashMap<>();
// 和上面的對應(yīng)
private final Map<String, Class<?>> getTypes = new HashMap<>();
// 記錄了默認(rèn)的構(gòu)造方法
private Constructor<?> defaultConstructor;
// 記錄了所有屬性名稱的集合
private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();
1.2 構(gòu)造方法
? 在Reflector的構(gòu)造器中會(huì)完成相關(guān)的屬性的初始化操作
// 解析指定的Class類型 并填充上述的集合信息
public Reflector(Class<?> clazz) {
type = clazz; // 初始化 type字段
addDefaultConstructor(clazz);// 設(shè)置默認(rèn)的構(gòu)造方法
addGetMethods(clazz);// 獲取getter方法
addSetMethods(clazz); // 獲取setter方法
addFields(clazz); // 處理沒有g(shù)etter/setter方法的字段
// 初始化 可讀屬性名稱集合
readablePropertyNames = getMethods.keySet().toArray(new String[0]);
// 初始化 可寫屬性名稱集合
writablePropertyNames = setMethods.keySet().toArray(new String[0]);
// caseInsensitivePropertyMap記錄了所有的可讀和可寫屬性的名稱 也就是記錄了所有的屬性名稱
for (String propName : readablePropertyNames) {
// 屬性名稱轉(zhuǎn)大寫
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
for (String propName : writablePropertyNames) {
// 屬性名稱轉(zhuǎn)大寫
caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
}
}
反射我們也可以在項(xiàng)目中我們直接拿來使用,定義一個(gè)普通的Bean對象。
/**
* 反射工具箱
* 測試用例
*/
public class Person {
private Integer id;
private String name;
public Person(Integer id) {
this.id = id;
}
public Person(Integer id, String name) {
this.id = id;
this.name = name;
}
}
測試
1.3 公共的API方法
然后我們可以看看Reflector中提供的公共的API方法
了解了Reflector對象的基本信息后我們需要如何來獲取Reflector對象呢?在MyBatis中給我們提供了一個(gè)ReflectorFactory工廠對象。所以我們先來簡單了解下ReflectorFactory對象,當(dāng)然你也可以直接new 出來,像上面的案例一樣
2 ReflectorFactory
ReflectorFactory接口主要實(shí)現(xiàn)了對Reflector對象的創(chuàng)建和緩存。
2.1 ReflectorFactory接口的定義
? 接口的定義如下
public interface ReflectorFactory {
// 檢測該ReflectorFactory是否緩存了Reflector對象
boolean isClassCacheEnabled();
// 設(shè)置是否緩存Reflector對象
void setClassCacheEnabled(boolean classCacheEnabled);
// 創(chuàng)建指定了Class的Reflector對象
Reflector findForClass(Class<?> type);
}
然后我們來看看它的具體實(shí)現(xiàn)
2.2 DefaultReflectorFactory
? MyBatis只為該接口提供了DefaultReflectorFactory這一個(gè)實(shí)現(xiàn)類。他與Reflector的關(guān)系如下
DefaultReflectorFactory中的實(shí)現(xiàn),代碼比較簡單,我們直接貼出來
public class DefaultReflectorFactory implements ReflectorFactory {
private boolean classCacheEnabled = true;
// 實(shí)現(xiàn)對 Reflector 對象的緩存
private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<>();
public DefaultReflectorFactory() {
}
@Override
public boolean isClassCacheEnabled() {
return classCacheEnabled;
}
@Override
public void setClassCacheEnabled(boolean classCacheEnabled) {
this.classCacheEnabled = classCacheEnabled;
}
@Override
public Reflector findForClass(Class<?> type) {
if (classCacheEnabled) {// 開啟緩存
// synchronized (type) removed see issue #461
return reflectorMap.computeIfAbsent(type, Reflector::new);
} else {
// 沒有開啟緩存就直接創(chuàng)建
return new Reflector(type);
}
}
}
2.3 使用演示
通過上面的介紹,我們可以具體的來使用下,加深對其的理解,先準(zhǔn)備一個(gè)JavaBean,
package com.gupaoedu.domain;
public class Student {
public Integer getId() {
return 6;
}
public void setId(Integer id) {
System.out.println(id);
}
public String getUserName() {
return "張三";
}
}
這個(gè)Bean我們做了簡單的處理
@Test
public void test02() throws Exception{
ReflectorFactory factory = new DefaultReflectorFactory();
Reflector reflector = factory.findForClass(Student.class);
System.out.println("可讀屬性:"+Arrays.toString(reflector.getGetablePropertyNames()));
System.out.println("可寫屬性:"+Arrays.toString(reflector.getSetablePropertyNames()));
System.out.println("是否具有默認(rèn)的構(gòu)造器:" + reflector.hasDefaultConstructor());
System.out.println("Reflector對應(yīng)的Class:" + reflector.getType());
}
3 Invoker
針對于Class中Field和Method的調(diào)用,在MyBatis中封裝了Invoker對象來統(tǒng)一處理(有使用到適配器模式)
3.1 接口說明
/**
* @author Clinton Begin
*/
public interface Invoker {
// 執(zhí)行Field或者M(jìn)ethod
Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;
// 返回屬性相應(yīng)的類型
Class<?> getType();
}
該接口有對應(yīng)的三個(gè)實(shí)現(xiàn)
3.2 效果演示
使用效果演示,還是通過上面的案例來介紹
package com.gupaoedu.domain;
public class Student {
public Integer getId() {
System.out.println("讀取id");
return 6;
}
public void setId(Integer id) {
System.out.println("寫入id:"+id);
}
public String getUserName() {
return "張三";
}
}
測試代碼
public void test03() throws Exception{
ReflectorFactory factory = new DefaultReflectorFactory();
Reflector reflector = factory.findForClass(Student.class);
// 獲取構(gòu)造器 生成對應(yīng)的對象
Object o = reflector.getDefaultConstructor().newInstance();
MethodInvoker invoker1 = (MethodInvoker) reflector.getSetInvoker("id");
invoker1.invoke(o,new Object[]{999});
// 讀取
Invoker invoker2 = reflector.getGetInvoker("id");
invoker2.invoke(o,null);
}
效果
4 MetaClass
在Reflector中可以針對普通的屬性操作,但是如果出現(xiàn)了比較復(fù)雜的屬性,比如 private Person person; 這種,我們要查找的表達(dá)式 person.userName.針對這種表達(dá)式的處理,這時(shí)就可以通過MetaClass來處理了。我們來看看主要的屬性和構(gòu)造方法
/**
* 通過 Reflector 和 ReflectorFactory 的組合使用 實(shí)現(xiàn)對復(fù)雜的屬性表達(dá)式的解析
* @author Clinton Begin
*/
public class MetaClass {
// 緩存 Reflector
private final ReflectorFactory reflectorFactory;
// 創(chuàng)建 MetaClass時(shí) 會(huì)指定一個(gè)Class reflector會(huì)記錄該類的相關(guān)信息
private final Reflector reflector;
private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
this.reflectorFactory = reflectorFactory;
this.reflector = reflectorFactory.findForClass(type);
}
// ....
}
效果演示,準(zhǔn)備Bean對象
package com.gupaoedu.domain;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class RichType {
private RichType richType;
private String richField;
private String richProperty;
private Map richMap = new HashMap();
private List richList = new ArrayList() {
{
add("bar");
}
};
public RichType getRichType() {
return richType;
}
public void setRichType(RichType richType) {
this.richType = richType;
}
public String getRichProperty() {
return richProperty;
}
public void setRichProperty(String richProperty) {
this.richProperty = richProperty;
}
public List getRichList() {
return richList;
}
public void setRichList(List richList) {
this.richList = richList;
}
public Map getRichMap() {
return richMap;
}
public void setRichMap(Map richMap) {
this.richMap = richMap;
}
}
測試代碼
@Test
public void test7(){
ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory);
System.out.println(meta.hasGetter("richField"));
System.out.println(meta.hasGetter("richProperty"));
System.out.println(meta.hasGetter("richList"));
System.out.println(meta.hasGetter("richMap"));
System.out.println(meta.hasGetter("richList[0]"));
System.out.println(meta.hasGetter("richType"));
System.out.println(meta.hasGetter("richType.richField"));
System.out.println(meta.hasGetter("richType.richProperty"));
System.out.println(meta.hasGetter("richType.richList"));
System.out.println(meta.hasGetter("richType.richMap"));
System.out.println(meta.hasGetter("richType.richList[0]"));
// findProperty 智能處理 . 的表達(dá)式
System.out.println(meta.findProperty("richType.richProperty"));
System.out.println(meta.findProperty("richType.richProperty1"));
System.out.println(meta.findProperty("richList[0]"));
System.out.println(Arrays.toString(meta.getGetterNames()));
}
輸出結(jié)果
true
true
true
true
true
true
true
true
true
true
true
richType.richProperty
richType.
null
[richType, richProperty, richMap, richList, richField]
5 MetaObject
我們可以通過MetaObject對象解析復(fù)雜的表達(dá)式來對提供的對象進(jìn)行操作。具體的通過案例來演示會(huì)更直觀些
@Test
public void shouldGetAndSetField() {
RichType rich = new RichType();
MetaObject meta = SystemMetaObject.forObject(rich);
meta.setValue("richField", "foo");
System.out.println(meta.getValue("richField"));
}
@Test
public void shouldGetAndSetNestedField() {
RichType rich = new RichType();
MetaObject meta = SystemMetaObject.forObject(rich);
meta.setValue("richType.richField", "foo");
System.out.println(meta.getValue("richType.richField"));
}
@Test
public void shouldGetAndSetMAppairUsingArraySyntax() {
RichType rich = new RichType();
MetaObject meta = SystemMetaObject.forObject(rich);
meta.setValue("richMap[key]", "foo");
System.out.println(meta.getValue("richMap[key]"));
}
以上三個(gè)方法的輸出結(jié)果都是
foo
6 反射模塊應(yīng)用
然后我們來看下在MyBatis的核心處理層中的實(shí)際應(yīng)用
6.1 SqlSessionFactory
在創(chuàng)建SqlSessionFactory操作的時(shí)候會(huì)完成Configuration對象的創(chuàng)建,而在Configuration中默認(rèn)定義的ReflectorFactory的實(shí)現(xiàn)就是DefaultReflectorFactory對象
然后在解析全局配置文件的代碼中,給用戶提供了ReflectorFactory的擴(kuò)展,也就是我們在全局配置文件中可以通過<reflectorFactory>標(biāo)簽來使用我們自定義的ReflectorFactory
6.2 SqlSession
? 無相關(guān)操作
6.3 Mapper
? 無相關(guān)操作
6.4 執(zhí)行SQL
? 在Statement獲取結(jié)果集后,在做結(jié)果集映射的使用有使用到,在DefaultResultSetHandler的createResultObject方法中。
然后在DefaultResultSetHandler的getRowValue方法中在做自動(dòng)映射的時(shí)候
繼續(xù)跟蹤,在createAutomaticMappings方法中
當(dāng)然還有很多其他的地方在使用反射模塊來完成的相關(guān)操作,這些可自行查閱
好了-反射模塊我們就給大家介紹到這里,如果有問題歡迎留言交流,歡迎大家點(diǎn)贊關(guān)注