Mybatis源碼分析篇------Reflector

Mybatis在進行參數處理、結果映射等操做時,會涉及不少反射的操做。Mybatis源碼中的對應反射模塊的部分叫作Reflector.首先咱們先分清屬性和字段這兩個概念:函數

  • 字段----類中定義的成員變量
  • 屬性----屬性則是經過Getter和Setter方法得到的,跟有沒有這個成員變量沒有關係。

下面咱們就開始分析這個反射模塊(注意:下面分析的源碼的Mybatis的版本是3.4.6,若是有什麼錯誤,歡迎你們在評論指出):cdn

字段

構造函數

  • type:初始化type字段
  • addDefaultConstructor():獲取默認構造函數。
  • addGetMethods():處理目標class中的Getter方法,填充getMethods和getTypes字段。
  • addSetMethods():處理目標class中的Setter方法,填充setMethods和setTypes字段。
  • addFields():處理目標class中沒有Getter和Setter方法的字段。
  • caseInsensitivePropertyMap:初始化caseinsensitivePropertyMap集合,其中記錄了全部大寫格式的屬性名稱。

addGetMethods()

源碼圖示對象

大體流程:blog

  1. 首先獲取當前目標類及其父類的定義的全部方法的惟一簽名及其Method對象,對應的方法爲getClassMethods()

  1. 當子類覆蓋了父類的Getter方法且返回值發生了變化,在第1步就會出現兩個不一樣的簽名,這顯然不符合咱們的預期要求。全部便會調用resolveGetterConflicts()方法解決衝突
private void resolveGetterConflicts(Map> conflictingGetters) {
    for (Entry> entry : conflictingGetters.entrySet()) {
      Method winner = null;
      String propName = entry.getKey();
      for (Method candidate : entry.getValue()) {
        if (winner == null) {
          winner = candidate;
          continue;
        }
        Class winnerType = winner.getReturnType();
        Class candidateType = candidate.getReturnType();
        if (candidateType.equals(winnerType)) {
          if (!boolean.class.equals(candidateType)) {
            throw new ReflectionException(
                "Illegal overloaded getter method with ambiguous type for property "
                    + propName + " in class " + winner.getDeclaringClass()
                    + ". This breaks the JavaBeans specification and can cause unpredictable results.");
          } else if (candidate.getName().startsWith("is")) {
            winner = candidate;
          }
        } else if (candidateType.isAssignableFrom(winnerType)) {
          // OK getter type is descendant
        } else if (winnerType.isAssignableFrom(candidateType)) {
          winner = candidate;
        } else {
          throw new ReflectionException(
              "Illegal overloaded getter method with ambiguous type for property "
                  + propName + " in class " + winner.getDeclaringClass()
                  + ". This breaks the JavaBeans specification and can cause unpredictable results.");
        }
      }
      addGetMethod(propName, winner);
    }
  }

addSetMethods() 邏輯與 addGetMethods() 差很少,我就不在重複敘述了。遞歸

addFields()會將這些沒有get set方法的字段添加到 setMethods() getMethods()的集合中,邏輯以下面:

    private void addFields(Class clazz) {
        //獲取目標class中的所有字段
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (canAccessPrivateMethods()) {
                try {
                    field.setAccessible(true);
                } catch (Exception e) {

                }
            }
            if (field.isAccessible()) {
                //判斷在setmethod 中是否已經處在有這個屬性了
                if (!setMethods.containsKey(field.getName())) {
                    int modifiers = field.getModifiers();
                    if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) {
                        //若是這個屬性不是Final或者靜態,將其添加在setmethod和settype中
                        addSetField(field);
                    }
                }
                if (!getMethods.containsKey(field.getName())) {
                    //若是這個屬性不是Final或者靜態,將其添加在getmethod和gettype中
                    addGetField(field);
                }
            }
        }
        //檢查是否有父類,繼續遞歸執行該過程
        if (clazz.getSuperclass() != null) {
            addFields(clazz.getSuperclass());
        }
    }

結語:上面就是Mybatis關於反射模塊比較重要的一個類的初始化過程

相關文章
相關標籤/搜索