mybatis-reflection反射包解析

反射包解析

概述

mybatis反射包,提供了反射相關的工具,爲啥要提供這些工具呢,java不是已經提供反射的功能了嗎?

java反射雖然已經很強大,但是api偏底層,要想使用好可能會需要大量重複代碼,可能使用不當也會產生性能問題,因此mybatis提供反射包提煉、封裝、增強反射api,讓上層應用用的更舒心。

包內容:

在這裏插入圖片描述

接下來會挑重點的類講解下原理。

Invoker

invoker單獨有一個子包,概念比較獨立,也比較簡單,代表執行器。包裝了Method、Field的執行

在這裏插入圖片描述

Invoker定義:

public interface Invoker {
  Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;

  Class<?> getType();
}

主要定義了一個invoke方法,和Method.invoke幾乎一樣,這裏做了抽象主要是把Field給包了進來。

GetFieldInvoker的invoke實現爲 field.get(target,arg)

SetFieldInvoker的invoke實現爲 field.set(target,arg)

factory

這裏的工廠子包只包含了ObjectFactory和其實現類DefaultObjectFactory。

public interface ObjectFactory {

  default void setProperties(Properties properties) {
    // NOP
  }
  <T> T create(Class<T> type);
  <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
  <T> boolean isCollection(Class<T> type);

}

就是通用的對象創建工廠,DefaultObjectFactory就是用構造函數去實例化對象,比較簡單。

property

這個子包主要提供對類屬性的反射解析工具。重點是PropertyTokenizer,意思是屬性分隔解析器。

解析格式例如:order[0].item[name].firstName這樣的表達式,有點類似json表達式,mybatis通過此類提供了表達式解析的能力,在處理嵌套屬性時更加方便和通用。

public class PropertyTokenizer implements Iterator<PropertyTokenizer> {
  /**
   * 當前屬性
   */
  private String name;

  /**
   * 當前完整分詞
   */
  private final String indexedName;

  /**
   * 索引值
   * 如果是數組[0],則是0
   * 如果是map[key],則是key、
   */
  private String index;

  /**
   * 剩餘字符串
   */
  private final String children;

  /**
   *  構造函數內部就完成解析
   */
  public PropertyTokenizer(String fullname) {
    int delim = fullname.indexOf('.');
    if (delim > -1) {
      name = fullname.substring(0, delim);
      children = fullname.substring(delim + 1);
    } else {
      name = fullname;
      children = null;
    }
    indexedName = name;
    delim = name.indexOf('[');
    if (delim > -1) {
      index = name.substring(delim + 1, name.length() - 1);
      name = name.substring(0, delim);
    }
  }

  @Override
  public boolean hasNext() {
    return children != null;
  }

  @Override
  public PropertyTokenizer next() {
    return new PropertyTokenizer(children);
  }

  @Override
  public void remove() {
    throw new UnsupportedOperationException("Remove is not supported, as it has no meaning in the context of properties.");
  }

PropertyTokenizer使用了迭代器模式實現了遞歸解析子串,挺巧妙,之後有類似遞歸的需求可以借鑑一下,代碼簡單清晰。

數據:order[0].item[name].firstName

解析結果:

name=orde

indexedName=order[0]

index=0

children=item[name].firstName

結果簡單清晰明瞭,有相關場景可以直接使用。

Reflector

Reflector反射器,保存類反射元數據

public class Reflector {
  /**
   * 對應的類
   */
  private final Class<?> type;
  /**
   * 可讀的屬性名集合
   */
  private final String[] readablePropertyNames;
  /**
   * 可寫的屬性名集合
   */
  private final String[] writablePropertyNames;
  /**
   * 所有set方法,
   */
  private final Map<String, Invoker> setMethods = new HashMap<>();
  /**
   * 所有get方法
   */
  private final Map<String, Invoker> getMethods = new HashMap<>();
  /**
   * set方法的入參類型
   */
  private final Map<String, Class<?>> setTypes = new HashMap<>();
  /**
   * get方法的返回類型
   */
  private final Map<String, Class<?>> getTypes = new HashMap<>();
  /**
   * 默認構造函數
   */
  private Constructor<?> defaultConstructor;
  /**
   * 不區分大小寫的屬性集合
   * key 屬性名全大寫, value 屬性名
   */
  private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();

相關屬性都是在構造函數中通過Class對象加工獲取的,基本包含了操作類的元數據。額外提供了不區分大小寫的屬性集合,爲了屬性查找、下劃線轉駝峯提供支持。

總結就是Class類增強,提供對property的一些簡便操作方法。

ReflectorFactory

Reflector工廠,就是控制Reflector的創建,目的是爲了緩存Reflector,Reflector雖好用,但是其創建過程比較重,使用了java的反射api,如果對同一class頻繁創建性能會被影響,且反射元數據也不會更改,緩存其是必須的。

DefaultReflectorFactory直接使用HashMap緩存Reflector,key是Class,value是Reflector。

MetaClass

MetaClass又是Reflector的增強類,包含了Reflector和ReflectorFactory,又額外提供了對屬性表達式的解析。

public class MetaClass {
  private final ReflectorFactory reflectorFactory;
  private final Reflector reflector;
}

上層應用使用MetaClass操作類,MetaClass內部使用ReflectorFactory緩存。

提供一些property相關的方法,實現委託給Reflector完成。

在這裏插入圖片描述

涉及屬性表達式解析則交給PropertyTokenizer。

Wapper

wapper包,放着ObjectWapper及其實現類。對象包裝器,在一個具體對象實例上添加反射功能,上面的Reflector、MetaClass都是在對靜態Class各種操作,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);

單看提供的方法比較簡單,屬性動態設置/獲取,屬性查找、getter/setter方法操作。

在這裏插入圖片描述

BaseWrapper

在這裏插入圖片描述

提供了集合的通用方法,屬性轉換集合、獲取/設置集合中的值。

BeanWrapper

普通Bean包裝器

public class BeanWrapper extends BaseWrapper {

  private final Object object;
  private final MetaClass metaClass;
}

具體對象object、MetaClass包裝,MetaClass的具象化。

藉助MetaClass實現ObjectWapper定義的方法,比較簡單。

@Override
public Object get(PropertyTokenizer prop) {
  // index不爲空代表是集合類型
  if (prop.getIndex() != null) {
    // 解析集合的值
    Object collection = resolveCollection(prop, object);
    return getCollectionValue(prop, collection);
  } else {
    return getBeanProperty(prop, object);
  }
}

get和set方法都有對集合類型的處理。

MetaObject

對象元數據,對ObjectWapper的進一步增強,表達式解析反射完全支持。

最主要兩個方法getValue、setValue

public Object getValue(String name) {
  PropertyTokenizer prop = new PropertyTokenizer(name);
  // 如果有子串遞歸解析
  if (prop.hasNext()) {
    // 獲取當前層值的MetaObject
    MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
    if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
      return null;
    } else {
      // 遞歸解析子串的值
      return metaValue.getValue(prop.getChildren());
    }
  } else {
    return objectWrapper.get(prop);
  }
}
public void setValue(String name, Object value) {
  PropertyTokenizer prop = new PropertyTokenizer(name);
  if (prop.hasNext()) {
    MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
    if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
      if (value == null) {
        // don't instantiate child path if value is null
        return;
      } else {
        metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
      }
    }
    metaValue.setValue(prop.getChildren(), value);
  } else {
    objectWrapper.set(prop, value);
  }
}

在複雜對象時可以方便的通過表達式,反射設置、獲取值。

總結

反射包重點在於Reflector、MetaClass、ObjectWapper、MetaObject的設計,職責清晰一層一層加強,遵守單一原則,在我們日常業務實現設計時值得借鑑。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章