mybaits原始碼分析--反射模組(二)
1.反射模組
MyBatis在進行引數處理、結果集對映等操作時會使用到大量的反射操作,Java中的反射功能雖然強大,但是程式碼編寫起來比較複雜且容易出錯,為了簡化反射操作的相關程式碼,MyBatis提供了專門的反射模組,該模組位於org.apache.ibatis.reflection包下,它對常見的反射操作做了進一步的封裝,提供了更加簡潔方便的反射API。
1.1 Reflector
Reflector是反射模組的基礎,每個Reflector物件都對應一個類,在Reflector中快取了反射需要使用的類的元資訊
1.1.1 屬性
首先看下Reflector類中提供的相關屬性的含義
//對應的Class 型別 1 private final Class<?> type; // 可讀屬性的名稱集合 可讀屬性就是存在 getter方法的屬性,初始值為null private final String[] readablePropertyNames; // 可寫屬性的名稱集合 可寫屬性就是存在 setter方法的屬性,初始值為null private final String[] writablePropertyNames; // 記錄了屬性相應的setter方法,key是屬性名稱,value是Invoker方法 // 他是對setter方法對應Method物件的封裝private final Map<String, Invoker> setMethods = new HashMap<>(); // 屬性相應的getter方法 private final Map<String, Invoker> getMethods = new HashMap<>(); // 記錄了相應setter方法的引數型別,key是屬性名稱 value是setter方法的引數型別 private final Map<String, Class<?>> setTypes = new HashMap<>();// 和上面的對應 private final Map<String, Class<?>> getTypes = new HashMap<>(); // 記錄了預設的構造方法 private Constructor<?> defaultConstructor; // 記錄了所有屬性名稱的集合 private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();
1.1.2 構造方法
在Reflector的構造器中會完成相關的屬性的初始化操作
// 解析指定的Class型別 並填充上述的集合資訊 public Reflector(Class<?> clazz) { type = clazz; // 初始化 type欄位 addDefaultConstructor(clazz);// 設定預設的構造方法 addGetMethods(clazz);// 獲取getter方法 addSetMethods(clazz); // 獲取setter方法 addFields(clazz); // 處理沒有getter/setter方法的欄位 // 初始化 可讀屬性名稱集合 readablePropertyNames = getMethods.keySet().toArray(new String[0]); // 初始化 可寫屬性名稱集合 writablePropertyNames = setMethods.keySet().toArray(new String[0]); // caseInsensitivePropertyMap記錄了所有的可讀和可寫屬性的名稱 也就是記錄了所有的屬性名稱 for (String propName : readablePropertyNames) { // 屬性名稱轉大寫 caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName); } for (String propName : writablePropertyNames) { // 屬性名稱轉大寫 caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName); } }
反射我們也可以在專案中我們直接拿來使用,定義一個普通的Bean物件。
1.1.3 公共的API方法
然後看看Reflector中提供的公共的API方法
方法名稱 | 作用 |
getType | 獲取Reflector表示的Class |
getDefaultConstructor | 獲取預設的構造器 |
hasDefaultConstructor | 判斷是否有預設的構造器 |
getSetInvoker | 根據屬性名稱獲取對應的Invoker 物件 |
getGetInvoker | 根據屬性名稱獲取對應的Invoker物件 |
getSetterType |
獲取屬性對應的型別 比如: |
getGetterType | 與上面是對應的 |
getGetablePropertyNames | 獲取所有的可讀屬性名稱的集合 |
getSetablePropertyNames | 獲取所有的可寫屬性名稱的集合 |
hasSetter | 判斷是否具有某個可寫的屬性 |
hasGetter | 判斷是否具有某個可讀的屬性 |
findPropertyName | 根據名稱查詢屬性 |
瞭解了Reflector物件的基本資訊後接下需要知道的就是如何來獲取Reflector物件,在MyBatis中給我們提供了一個ReflectorFactory工廠物件。所以先來簡單瞭解下ReflectorFactory物件,當然也可以直接new 出來,像上面的案例一樣
1.2 ReflectorFactory
ReflectorFactory介面主要實現了對Reflector物件的建立和快取。
1.2.1 ReflectorFactory介面的定義
介面的定義如下
public interface ReflectorFactory { // 檢測該ReflectorFactory是否快取了Reflector物件 boolean isClassCacheEnabled(); // 設定是否快取Reflector物件 void setClassCacheEnabled(boolean classCacheEnabled); // 建立指定了Class的Reflector物件 Reflector findForClass(Class<?> type); }
然後看看它的具體實現
DefaultReflectorFactory中的實現,程式碼比較簡單
public class DefaultReflectorFactory implements ReflectorFactory { private boolean classCacheEnabled = true; // 實現對 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 { // 沒有開啟快取就直接建立 return new Reflector(type); } } }
1.2.3 使用演示
public class User implements Serializable { private Integer id; private String userName; private String realName; private String password; private Integer age; private Integer dId; private Dept dept; public Integer getId() { return 2; } public void setId(Integer id) { System.out.println(id); } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getRealName() { return realName; } public void setRealName(String realName) { this.realName = realName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Integer getdId() { return dId; } public void setdId(Integer dId) { this.dId = dId; } public Dept getDept() { return dept; } public void setDept(Dept dept) { this.dept = dept; } }
/** * ReflectorFactory功能演示 * @throws Exception */ @Test public void test01() throws Exception{ ReflectorFactory factory=new DefaultReflectorFactory(); Reflector reflector=factory.findForClass(User.class); System.out.println("可讀"+ Arrays.toString(reflector.getGetablePropertyNames())); System.out.println("可寫"+ Arrays.toString(reflector.getSetablePropertyNames())); System.out.println("是否有預設構造器"+reflector.hasDefaultConstructor()); System.out.println("Reflector對應的class"+reflector.getType()); }
1.3 Invoker
針對於Class中Field和Method的呼叫,在MyBatis中封裝了Invoker物件來統一處理(有使用到介面卡模式)
1.3.1 介面說明
public interface Invoker { // 執行Field或者Method Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException; // 返回屬性相應的型別 Class<?> getType(); }
這個介面對應有三個實現
1.3.2 效果演示
public class User { public Integer getId() { System.out.println("讀取id"); return 6; } public void setId(Integer id) { System.out.println("寫入id:"+id); } public String getUserName() { return "張三"; } }
@Test
public void test02() throws Exception{
ReflectorFactory factory = new DefaultReflectorFactory();
Reflector reflector = factory.findForClass(User.class);
//獲取構造器 生成對應物件
Object o = reflector.getDefaultConstructor().newInstance();
org.apache.ibatis.reflection.invoker.Invoker invoker1=reflector.getSetInvoker("id");
invoker1.invoke ( o ,new Object[] { 999 });
/* 讀取 */
org.apache.ibatis.reflection.invoker.Invoker invoker2= reflector.getGetInvoker("id");
invoker2.invoke( o,null);
}
}
1.4 MetaClass
在Reflector中可以針對普通的屬性操作,但是如果出現了比較複雜的屬性,比如 private Person person; 這種,我們要查詢的表示式 person.userName.針對這種表示式的處理,這時就可以通過MetaClass來處理了。我們來看看主要的屬性和構造方法
/** * 通過 Reflector 和 ReflectorFactory 的組合使用 實現對複雜的屬性表示式的解析 * @author Clinton Begin */ public class MetaClass { // 快取 Reflector private final ReflectorFactory reflectorFactory; // 建立 MetaClass時 會指定一個Class reflector會記錄該類的相關資訊 private final Reflector reflector; private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) { this.reflectorFactory = reflectorFactory; this.reflector = reflectorFactory.findForClass(type); } public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) { return new MetaClass(type, reflectorFactory); } public MetaClass metaClassForProperty(String name) { Class<?> propType = reflector.getGetterType(name); return MetaClass.forClass(propType, reflectorFactory); } public String findProperty(String name) { StringBuilder prop = buildProperty(name, new StringBuilder()); return prop.length() > 0 ? prop.toString() : null; } public String findProperty(String name, boolean useCamelCaseMapping) { if (useCamelCaseMapping) { name = name.replace("_", ""); } return findProperty(name); } public String[] getGetterNames() { return reflector.getGetablePropertyNames(); } public String[] getSetterNames() { return reflector.getSetablePropertyNames(); } public Class<?> getSetterType(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaClass metaProp = metaClassForProperty(prop.getName()); return metaProp.getSetterType(prop.getChildren()); } else { return reflector.getSetterType(prop.getName()); } } public Class<?> getGetterType(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaClass metaProp = metaClassForProperty(prop); return metaProp.getGetterType(prop.getChildren()); } // issue #506. Resolve the type inside a Collection Object return getGetterType(prop); } private MetaClass metaClassForProperty(PropertyTokenizer prop) { Class<?> propType = getGetterType(prop); return MetaClass.forClass(propType, reflectorFactory); } private Class<?> getGetterType(PropertyTokenizer prop) { Class<?> type = reflector.getGetterType(prop.getName()); if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) { Type returnType = getGenericGetterType(prop.getName()); if (returnType instanceof ParameterizedType) { Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments(); if (actualTypeArguments != null && actualTypeArguments.length == 1) { returnType = actualTypeArguments[0]; if (returnType instanceof Class) { type = (Class<?>) returnType; } else if (returnType instanceof ParameterizedType) { type = (Class<?>) ((ParameterizedType) returnType).getRawType(); } } } } return type; } private Type getGenericGetterType(String propertyName) { try { Invoker invoker = reflector.getGetInvoker(propertyName); if (invoker instanceof MethodInvoker) { Field _method = MethodInvoker.class.getDeclaredField("method"); _method.setAccessible(true); Method method = (Method) _method.get(invoker); return TypeParameterResolver.resolveReturnType(method, reflector.getType()); } else if (invoker instanceof GetFieldInvoker) { Field _field = GetFieldInvoker.class.getDeclaredField("field"); _field.setAccessible(true); Field field = (Field) _field.get(invoker); return TypeParameterResolver.resolveFieldType(field, reflector.getType()); } } catch (NoSuchFieldException | IllegalAccessException ignored) { } return null; } public boolean hasSetter(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { if (reflector.hasSetter(prop.getName())) { MetaClass metaProp = metaClassForProperty(prop.getName()); return metaProp.hasSetter(prop.getChildren()); } else { return false; } } else { return reflector.hasSetter(prop.getName()); } } public boolean hasGetter(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { if (reflector.hasGetter(prop.getName())) { MetaClass metaProp = metaClassForProperty(prop); return metaProp.hasGetter(prop.getChildren()); } else { return false; } } else { return reflector.hasGetter(prop.getName()); } } public Invoker getGetInvoker(String name) { return reflector.getGetInvoker(name); } public Invoker getSetInvoker(String name) { return reflector.getSetInvoker(name); } private StringBuilder buildProperty(String name, StringBuilder builder) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { String propertyName = reflector.findPropertyName(prop.getName()); if (propertyName != null) { builder.append(propertyName); builder.append("."); MetaClass metaProp = metaClassForProperty(propertyName); metaProp.buildProperty(prop.getChildren(), builder); } } else { String propertyName = reflector.findPropertyName(name); if (propertyName != null) { builder.append(propertyName); } } return builder; } public boolean hasDefaultConstructor() { return reflector.hasDefaultConstructor(); } }
效果演示,準備Bean物件
public class RichType { private RichType richType; private String richField; private String richProperty; private Map richMap = new HashMap (); private List richList = new ArrayList () { { add("小傢伙要記得學習"); } }; 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; } }
/** * MetaClass功能演示 * @throws Exception */ @Test public void test03() throws Exception{ ReflectorFactory factory = new DefaultReflectorFactory(); MetaClass metaClass=MetaClass.forClass ( RichType.class,factory); System.out.println(metaClass.hasGetter("richField")); System.out.println(metaClass.hasGetter("richProperty")); System.out.println(metaClass.hasGetter("richList")); System.out.println(metaClass.hasGetter("richMap")); System.out.println(metaClass.hasGetter("richList[0]")); System.out.println(metaClass.hasGetter("richType")); System.out.println(metaClass.hasGetter("richType.richField")); System.out.println(metaClass.hasGetter("richType.richProperty")); System.out.println(metaClass.hasGetter("richType.richList")); System.out.println(metaClass.hasGetter("richType.richMap")); System.out.println(metaClass.hasGetter("richType.richList[0]")); // findProperty 只能處理 . 的表示式 System.out.println(metaClass.findProperty("richType.richProperty")); System.out.println(metaClass.findProperty("richType.richProperty1")); System.out.println(metaClass.findProperty("richList[0]")); System.out.println(Arrays.toString(metaClass.getGetterNames())); }
1.5 MetaObject
可以通過MetaObject物件解析複雜的表示式來對提供的物件進行操作。具體的通過案例來演示會更直觀些
@Test public void test04() throws Exception{ RichType richType=new RichType (); MetaObject metaObject=SystemMetaObject.forObject ( richType ); metaObject.setValue ( "richField","李四" ); System.out.println (metaObject.getValue ( "richField" )); } @Test public void test05() throws Exception{ RichType richType=new RichType (); MetaObject metaObject=SystemMetaObject.forObject ( richType ); metaObject.setValue ( "richType.richField","李四1" ); System.out.println (metaObject.getValue ( "richType.richField" )); } @Test public void test06() throws Exception{ RichType richType=new RichType (); MetaObject metaObject=SystemMetaObject.forObject ( richType ); metaObject.setValue ( "richMap[0]","李四2" ); System.out.println (metaObject.getValue ( "richMap[0]" )); }
1.6 反射模組應用
看下在MyBatis的核心處理層中的實際應用
1.6.1 SqlSessionFactory
在建立SqlSessionFactory操作的時候會完成Configuration物件的建立,而在Configuration中預設定義的ReflectorFactory的實現就是DefaultReflectorFactory物件
然後在解析全域性配置檔案的程式碼中,給使用者提供了ReflectorFactory的擴充套件,也就是我們在全域性配置檔案中可以通過<reflectorFactory>標籤來使用我們自定義的ReflectorFactory
1.6.2 執行SQL
在Statement獲取結果集後,在做結果集對映的使用有使用到,在DefaultResultSetHandler的createResultObject方法中。
然後在DefaultResultSetHandler的getRowValue方法中在做自動對映的時候
繼續跟蹤,在createAutomaticMappings方法中
這短短的一生我們最終都會失去,不妨大膽一點,愛一個人,攀一座山,追一個夢