天天看點

聊聊mybatis的反射之Reflector類

聊聊mybatis的反射之Reflector類

反射是一塊重要的内容,java中的反射讓我們在程式運作的時候可以擷取到java對象的屬性和方法,mybatis有自己的反射工具箱子產品,下面我就簡單說一下mybatis 反射工具箱的一些類和方法

Reflector類是反射器,通過給出的測試類ReflectorTest我們可以知道這個類的具體用法:

@Test
  public void testGetSetterType() throws Exception {
    Reflector reflector = Reflector.forClass(Section.class);
    Assert.assertEquals(Long.class, reflector.getSetterType("id"));
  }
           

Reflector的構造方法

通過Reflector的構造器,我們也能知道,隻需要傳入Class對象,Reflector就能解析這個Class對象,并把Class類的資訊分類填充到Reflector類自定的一些成員變量中

private Reflector(Class<?> clazz) {
    type = clazz;
    //加入構造函數
    addDefaultConstructor(clazz);
    //加入getter
    addGetMethods(clazz);
    //加入setter
    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) {
        //這裡為了能找到某一個屬性,就把他變成大寫作為map的key。。。
      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
    }
    for (String propName : writeablePropertyNames) {
      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
    }
  }
           
  1. type記錄class的類型
  2. addDefaultConstructor是通過反射得到Class的無參構造方法
  3. addGetMethods()方法就是用來讀取Class的getter方法,然後放入getMethods集合中和getTypes集合中,
  4. addSetMethods()方法就是讀取Class檔案的setter方法,放入setMethods方法清單集合和setTypes類型清單集合中
  5. addFields()方法是針對class中沒有getter setter方法的字段生成GetFieldInvoker類來放入getMethods、getTypes、setMethods和setTypes集合中
  6. 然後初始化readablePropertyNames和writeablePropertyNames,readablePropertyNames是getter的屬性清單集合,writeablePropertyNames是setter的屬性清單集合
  7. 把readablePropertyNames和writeablePropertyNames中全部轉為大寫,儲存到caseInsensitivePropertyMap中,key是屬性名的大寫,value是屬性名

Reflector的 addGetMethods()

private void addGetMethods(Class<?> cls) {
    Map<String, List<Method>> conflictingGetters = new HashMap<String, List<Method>>();
    //這裡getter和setter都調用了getClassMethods,有點浪費效率了。不妨把addGetMethods,addSetMethods合并成一個方法叫addMethods
    Method[] methods = getClassMethods(cls);
    for (Method method : methods) {
      String name = method.getName();
      if (name.startsWith("get") && name.length() > 3) {
        if (method.getParameterTypes().length == 0) {
          name = PropertyNamer.methodToProperty(name);
          addMethodConflict(conflictingGetters, name, method);
        }
      } else if (name.startsWith("is") && name.length() > 2) {
        if (method.getParameterTypes().length == 0) {
          name = PropertyNamer.methodToProperty(name);
          addMethodConflict(conflictingGetters, name, method);
        }
      }
    }
    resolveGetterConflicts(conflictingGetters);
  }
           
  1. 調用getClassMethods(cls);擷取方法資訊,點進去這個方法可以看到定義了一個map集合

    Map<String, Method> uniqueMethods = new HashMap<String, Method>();

    它的key是傳回值類型#方法名稱:參數類型:參數類型。。。,value是Method對象,key保證全局唯一,使用map能進行去重
  2. 擷取到這些methods對象後,循環周遊,找出getter方法來,放入conflictingGetters集合中,key是屬性名。value是對應的getter方法的集合,為什麼是集合呢,因為有可能存在方法的重寫
  3. 最後resolveGetterConflicts()方法解決簽名的沖突,就是比較getter方法的傳回值,取子類的getter方法,在這個方法裡調用addGetMethod把對應的Method生成MethodInvoker對象儲存到getMethods中

總結

❤️ 感謝大家

  1. 歡迎關注我❤️,點贊??,評論?,轉發?