mybatis 與 反射

Mybatis是個優秀的ORM框架,因此它的反射層必定不會讓咱們失望緩存

圖比較大,能夠開新頁面查看app

能夠看到,Mybatis對這一塊抽象的比較複雜,咱們能夠看到有幾個比較主要的部分:Reflector、Invoker、PropertyTokenizer、MetaClass,MetaObject和ObjectWrapper,下面咱們一個一個解析這幾個部分,最後合併在一塊兒看看他們是如何協做工做的。框架

 

Reflector

我對Reflector的理解是 Reflector是對類的描述 ,咱們從一段UT開始(代碼位於ReflectorTest):ide

  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作的一個簡單的工廠,提供類反射的緩存(因此反射這塊的開銷基本上能夠不計了,既靈活又快捷)ui

DefaultReflectorFactory 是 Reflector的默認實現類,用一個ConcurrentMap緩存全部的Reflector示例,它的findForClass方法以下,它首先嚐試從map中獲取Reflector,獲取失敗調用Reflector的構造方法建立示例,緩存並返回:this

  @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的構造方法:spa

  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中,爲了後面的查找,大小寫不敏感。3d

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...)中還具備普遍的應用

相關文章
相關標籤/搜索