Mybatis是個優秀的ORM框架,所以它的反射層一定不會讓我們失望
圖比較大,可以開新頁面查看
可以看到,Mybatis對這一塊抽象的比較復雜,我們可以看到有幾個比較主要的部分:Reflector、Invoker、PropertyTokenizer、MetaClass,MetaObject和ObjectWrapper,下面我們一個一個解析這幾個部分,最后合並在一起看看他們是如何協作工作的。
Reflector
我對Reflector的理解是 Reflector是對類的描述 ,我們從一段UT開始(代碼位於ReflectorTest):
static interface Entity<T> { T getId(); void setId(T id); } static abstract class AbstractEntity implements Entity<Long> { private Long id; @Override public Long getId() { return id; } @Override public void setId(Long id) { this.id = id; } } static class Section extends AbstractEntity implements Entity<Long> { } @Test public void testGetSetterType() throws Exception { ReflectorFactory reflectorFactory = new DefaultReflectorFactory(); Reflector reflector = reflectorFactory.findForClass(Section.class); Assert.assertEquals(Long.class, reflector.getSetterType("id")); }
這個測試方法首先創建了個ReflectorFactory對象,然后用這個factory創建了一個Section類的Reflector,然后判斷Section類中id的setter方法是Long類型的。
ReflectorFactory是對Reflector做的一個簡單的工廠,提供類反射的緩存(所以反射這塊的開銷基本上可以不計了,既靈活又快捷)
DefaultReflectorFactory 是 Reflector的默認實現類,用一個ConcurrentMap緩存所有的Reflector示例,它的findForClass方法如下,它首先嘗試從map中獲取Reflector,獲取失敗調用Reflector的構造方法創建示例,緩存並返回:
@Override public Reflector findForClass(Class<?> type) { if (classCacheEnabled) { // synchronized (type) removed see issue #461 Reflector cached = reflectorMap.get(type); if (cached == null) { cached = new Reflector(type); reflectorMap.put(type, cached); } return cached; } else { return new Reflector(type); } }
,之后是Reflector的構造方法:
public Reflector(Class<?> clazz) { type = clazz; addDefaultConstructor(clazz); addGetMethods(clazz); addSetMethods(clazz); addFields(clazz); readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]); writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]); for (String propName : readablePropertyNames) { caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName); } for (String propName : writeablePropertyNames) { caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName); } }
這一塊不再細細展開,方法名見名知義,首先將type成員設置為原始的class對象,之后獲取class的構造方法,getter/setter屬性,成員字段,之后將屬性名轉大寫存放到caseInsensitivePropertyMap中,為了后面的查找,大小寫不敏感。
Reflector的其他方法就是對我們保存的這些類的描述做查找, 其中有兩個特別的,也就是我們接下來要討論的 getSetInvoker和 getGetInvoker
Invoker
Invoker,顧名思義,就是調用,可以調用的東西,他有一個invoke方法,意思就是調用,參數是target和args,就是調用的對象和調用的參數。
我們來看下它的幾個實現類:
MethodInvoker: 方法調用
SetFieldInvoker:Setter方法調用
GetFieldInvoker:Getter方法調用
MethodInvoker中invoke方法的實現:
@Override public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException { return method.invoke(target, args); }
就是簡單的method.invoke,
PropertyTokenizer
這個就比較牛逼了,他可以處理屬性表達式,PropertyTokenizer還實現了Iterator接口,這意味着他可以處理復雜的嵌套屬性
@Override public boolean hasNext() { return children != null; } @Override public PropertyTokenizer next() { return new PropertyTokenizer(children); }
字段的含義,name表示當前對象的名字,indexedName是當前對象的名字加上后面的索引([])如果有的話,index是索引下標,children是延伸屬性(子對象)
比如:用PropertyTokenizer去解析 "richType.richList[0].value",那么 name=richType, indexedName=richType,index=null,children=richList[0].value
之后執行tokenizer.next()得到新的tokenizer,此時 name=richList, indexdName=richList[0],index=0, children=value
之后我們會結合MetaClass和MetaObject看看他有多牛逼
MetaClass
MetaClass實際上是對Reflector和ProeprtyTokenizer的一種結合,是我們可以用復雜的屬性表達式來獲取類型的描述。
同樣的,我們結合UT來看看它是怎樣工作的,首先是一個示例的復雜類型 RichType
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 shouldCheckGetterExistance() { ReflectorFactory reflectorFactory = new DefaultReflectorFactory(); MetaClass meta = MetaClass.forClass(RichType.class, reflectorFactory); assertTrue(meta.hasGetter("richField")); assertTrue(meta.hasGetter("richProperty")); assertTrue(meta.hasGetter("richList")); assertTrue(meta.hasGetter("richMap")); assertTrue(meta.hasGetter("richList[0]")); assertTrue(meta.hasGetter("richType")); assertTrue(meta.hasGetter("richType.richField")); assertTrue(meta.hasGetter("richType.richProperty")); assertTrue(meta.hasGetter("richType.richList")); assertTrue(meta.hasGetter("richType.richMap")); assertTrue(meta.hasGetter("richType.richList[0]")); assertFalse(meta.hasGetter("[0]")); }
這段代碼說明了metaClass.hasGetter方法可以接受一個復雜的屬性表達式來找到對應的類型描述(利用PropertyTokenizer),這個神奇的功能是這么實現的:
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()); } }
首先檢查tokenizer的name字段對應的屬性是不是有getter方法,之后迭代子屬性,直到最后,children為空。
MetaClass中的還有幾個方法的實現和這個類似,hasSetter, getGetterType, getSetterType
以上都是類級別的反射抽象,下面看看對象級別的
ObjectWrapper
ObjectWrapper是對對象的描述的抽象,它抽象出一系列對對象描述的查詢和更新的接口
public interface ObjectWrapper { Object get(PropertyTokenizer prop); void set(PropertyTokenizer prop, Object value); String findProperty(String name, boolean useCamelCaseMapping); String[] getGetterNames(); String[] getSetterNames(); Class<?> getSetterType(String name); Class<?> getGetterType(String name); boolean hasSetter(String name); boolean hasGetter(String name); MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory); boolean isCollection(); void add(Object element); <E> void addAll(List<E> element); }
ObjectWrapper有個幾個實現類
BeanWrapper,包裝Javabean的描述,
MapWrapper,包裝Map(鍵值對)的描述
CollectionWrapper,包裝Collection(集合)的描述
ObjectWrapperFactory 了操作實例化ObjectWrapper的工廠方法的抽象,可自定義實現
private Object getBeanProperty(PropertyTokenizer prop, Object object) { try { Invoker method = metaClass.getGetInvoker(prop.getName()); try { return method.invoke(object, NO_ARGUMENTS); } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } catch (RuntimeException e) { throw e; } catch (Throwable t) { throw new ReflectionException("Could not get property '" + prop.getName() + "' from " + object.getClass() + ". Cause: " + t.toString(), t); } } private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) { try { Invoker method = metaClass.getSetInvoker(prop.getName()); Object[] params = {value}; try { method.invoke(object, params); } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } catch (Throwable t) { throw new ReflectionException("Could not set property '" + prop.getName() + "' of '" + object.getClass() + "' with value '" + value + "' Cause: " + t.toString(), t); } }
MetaObject
MetaObject也是對對象的描述,它代理了objectWrapper的大部分方法,和MetaClass一樣,它利用PropertyTokenizer做了對復雜屬性表達式的處理
@Test public void shouldGetAndSetNestedField() { RichType rich = new RichType(); MetaObject meta = SystemMetaObject.forObject(rich); meta.setValue("richType.richField", "foo"); assertEquals("foo", meta.getValue("richType.richField")); }
MetaObject有5個成員字段,
originalObject:原始對象,
objectWrapper,被包裝的objectWrapper,
objectFactory,對象創建工廠,用於在setValue方法中創建不存在的對象屬性實例,
objectWrapperFactory,創建特定的objectWrapper,
reflectorFactory,暫時不知道是干什么的
協作
反射層的類互相協作,最終根據入參制作出來一個完美的MetaObject和MetaClass給其他組件使用,這其中,比較重要的方法有:
Configuration.newMetaObject,根據傳入的object和配置的factory創建對象描述
實際上,ObjectFactory,ObjectWrapperFactory,ReflectorFactory是可以在XML中配置成自定義的,工廠對象全局單例(Configuration對象中),
private void parseConfiguration(XNode root) { try { //issue #117 read properties first propertiesElement(root.evalNode("properties")); Properties settings = settingsAsProperties(root.evalNode("settings")); loadCustomVfs(settings); typeAliasesElement(root.evalNode("typeAliases")); pluginElement(root.evalNode("plugins")); objectFactoryElement(root.evalNode("objectFactory")); objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); reflectorFactoryElement(root.evalNode("reflectorFactory")); settingsElement(settings); // read it after objectFactory and objectWrapperFactory issue #631 environmentsElement(root.evalNode("environments")); databaseIdProviderElement(root.evalNode("databaseIdProvider")); typeHandlerElement(root.evalNode("typeHandlers")); mapperElement(root.evalNode("mappers")); } catch (Exception e) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); } }
XMlConfigBuilder.settingsAsProperties方法使用MetaClass檢查Properties參數有沒有非法的key,
MetaObject和MetaClass在Session的執行周期(executor, mapping, builder...)中還具有廣泛的應用