MyBatis源碼解析 - 反射模塊

MyBatis源碼解析 - 反射模塊

1. 前言

? 該模塊位于org.apache.ibatis.reflection包中,MyBatis在進行參數(shù)處理拔稳、結果映射等操作時困肩,會涉及大量的反射操作锣咒。Java 中的反射雖然功能強大吐句,但是代碼編寫起來比較復雜且容易出錯试和,為了簡化反射操作的相關代碼,MyBatis提供了專門的反射模塊衅枫,它對常見的反射操作做了進一步封裝嫁艇,提供了更加簡潔方便的反射API。本節(jié)就來為讀者介紹該模塊中核心代碼的實現(xiàn)弦撩。

2. Reflector

Reflector 是MyBaits中反射模塊的基礎步咪,Reflector中緩存了很多反射操作需要使用的元數(shù)據(jù)。各個字段如下:

private final Class<?> type;  //對應的class類型
private final String[] readablePropertyNames; //可讀屬性的名稱集合益楼,可讀屬性就是存在相應getter方法的屬性
private final String[] writablePropertyNames; //可寫屬性的名稱集合猾漫,可寫屬性就是存在相應setter方法的屬性
//記錄了屬性相應的setter方法,key是屬性名稱感凤,value 是Invoker對象悯周,它是對setter方法對應
// Method 對象的封裝
private final Map<String, Invoker> setMethods = new HashMap<>();
//屬性相應的getter方法集合,key 是屬性名稱陪竿,value 也是Invoker對象
private final Map<String, Invoker> getMethods = new HashMap<>();
//記錄了屬性相應的setter方法的參數(shù)值類型禽翼,key是屬性名稱,value是setter方法的參數(shù)類型
private final Map<String, Class<?>> setTypes = new HashMap<>();
//記錄了屬性相應的getter方法的參數(shù)值類型族跛,key是屬性名稱闰挡,value是getter方法的參數(shù)類型
private final Map<String, Class<?>> getTypes = new HashMap<>();
//記錄了默認的構造函數(shù)
private Constructor<?> defaultConstructor;
//記錄了所有屬性名稱的集合
private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();

在Reflector的構造函數(shù)中,會解析指定的Class對象礁哄,并填充上述集合长酗,代碼如下:

public Reflector(Class<?> clazz) {
    type = clazz; //初始化type字段
    //查找默認構造函數(shù)(無參構造函數(shù))具體實現(xiàn)是以反射遍歷所有構造方法
    addDefaultConstructor(clazz);
    //處理class中的getter方法
    addGetMethods(clazz);
    //處理class中的setter方法
    addSetMethods(clazz);
    //處理沒有getter或setter方法的字段
    addFields(clazz);
    // 初始化為空數(shù)組
    readablePropertyNames = getMethods.keySet().toArray(new String[0]);
    // 初始化為空數(shù)組
    writablePropertyNames = setMethods.keySet().toArray(new String[0]);
    //初始化caseInsensitivePropertyMap集合 其中記錄了所有大寫格式的屬性名稱
    for (String propName : readablePropertyNames) {
      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
    }
    for (String propName : writablePropertyNames) {
      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
    }
  }

Reflector.addGetMethods()方法主要解析類中定義的getter方法,Reflector.addSetMethods()方法主要解析類中定義的setter方法桐绒,兩個類似夺脾,下面我們就以Reflector.addGetMethods()方法為例進行介紹,Reflector.addGetMethods()解析有下面三個步驟:

  1. 首先調(diào)用Reflector.getClassMethods()方法獲取當前類以及父類中定義的所有方法的唯一簽名以及相應的Method對象掏膏。

    private Method[] getClassMethods(Class<?> clazz) {
      //用于記錄指定類中定義的全部方法的唯一簽名對應的Method對象
      Map<String, Method> uniqueMethods = new HashMap<>();
      Class<?> currentClass = clazz;
      while (currentClass != null && currentClass != Object.class) {
        //記錄currentClass類中定義的全部方法
        addUniqueMethods(uniqueMethods, currentClass.getDeclaredMethods());
    
        // we also need to look for interface methods -
        // because the class may be abstract
        //記錄接口中定義一的方法
        Class<?>[] interfaces = currentClass.getInterfaces();
        for (Class<?> anInterface : interfaces) {
          addUniqueMethods(uniqueMethods, anInterface.getMethods());
        }
        //獲取父類繼續(xù)while循環(huán)
        currentClass = currentClass.getSuperclass();
      }
    
      Collection<Method> methods = uniqueMethods.values();
      //轉換成methods數(shù)組返回
      return methods.toArray(new Method[0]);
    }
    

    在Reflector.getClassMethods()方法中會為每個方法生成唯一簽名劳翰,并記錄到conflictingSetters集合中敦锌,實現(xiàn)如下:


private void addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods) {
  for (Method currentMethod : methods) {
    if (!currentMethod.isBridge()) {
      //通過getSignature()方法得到的方法簽名 規(guī)則:返回值類型#方法名稱:參數(shù)類型列表馒疹。
      //通過getSignature()方法得到的發(fā)放簽名是全局唯一的,可以作為該方法的唯一標識
      String signature = getSignature(currentMethod);
      // check to see if the method is already known
      // if it is known, then an extended class must have
      // overridden a method
      //檢測是否在子類中已經(jīng)添加過該方法【如果添加過就忽略】
      if (!uniqueMethods.containsKey(signature)) {
        //記錄該簽名和方法的對應關系
        uniqueMethods.put(signature, currentMethod);
      }
    }
  }
}

  1. 然后按照Java規(guī)范乙墙,從Reflector.getClassMethods()方法返回的Method數(shù)組中查找該類的getter方法颖变,記錄到conflictingSetters集合中√耄【該集合為HashMap<String,<List<Method>>>,key為屬性名稱腥刹,value是該屬性對應的setter集合『郝颍】

  2. 當子類覆蓋父類的getter方法且返回值發(fā)生變化時衔峰,在步驟【1】中就會產(chǎn)生兩個簽名不同的方法,在Reflector.addUniqueMethods()方法中會被當做兩個不同的方法添加到conflictingSetters集合中,這顯然不是我們要的結果垫卤,所以第三步我們會調(diào)用Reflector.resolveSetterConflicts()方法對這個覆寫的方法進行處理威彰,同時會將得到的getter方法記錄到getMethods集合,并將其返回值類型填充到getTypes集合穴肘。Reflector.resolveSetterConflicts()方法具體實現(xiàn)如下:


private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {
  // 遍歷 conflictingGetters 集合
  for (Entry<String, List<Method>> entry : conflictingGetters.entrySet()) {
    Method winner = null;
    //獲取屬性名
    String propName = entry.getKey();
    //是否是不明確的
    boolean isAmbiguous = false;
    //
    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)) {
          //不明確的類型 【不明確 拋異承危】
          isAmbiguous = true;
          break;
        } else if (candidate.getName().startsWith("is")) {
          //對于boolean類型
          //當前方法返回值是當前最合適的方法的返回值的子類
          winner = candidate;
        }
      } else if (candidateType.isAssignableFrom(winnerType)) {
        //當前最適合的方法的返回值是當前方法返回值的子類,什么都不做 當前最適合的方法 依然不變
        // OK getter type is descendant
      } else if (winnerType.isAssignableFrom(candidateType)) {  //當前返回值是當前最適合的方法的返回值的
        winner = candidate;
      } else {
        //不明確的類型 要拋異常
        isAmbiguous = true;
        break;
      }
    }
    addGetMethod(propName, winner, isAmbiguous);
  }
}

Reflector.addGetMethod()方法對getMethods集合和getTypes集合進行填充评抚,具體實現(xiàn)代碼如下:


private void addGetMethod(String name, Method method, boolean isAmbiguous) {
  //對于不明確的方法 拋異常處理
  MethodInvoker invoker = isAmbiguous
      ? new AmbiguousMethodInvoker(method, MessageFormat.format(
          "Illegal overloaded getter method with ambiguous type for property ''{0}'' in class ''{1}''. This breaks the JavaBeans specification and can cause unpredictable results.",
          name, method.getDeclaringClass().getName()))
      : new MethodInvoker(method);
  //將屬性名以及對應的MethodInvoker對象添加到getMethods集合中豹缀,Invoker的內(nèi)容后面解析
  getMethods.put(name, invoker);
  //獲取返回值的Type,TypeParameterResolver會在后面分析
  Type returnType = TypeParameterResolver.resolveReturnType(method, type);
  //將屬性名及其getter方法的返回值加到getTypes集合中保存渤弛,typeToClass()方法后面分析
  getTypes.put(name, typeToClass(returnType));
}

分析完Reflector.addGetMethods()的三個核心步驟后视哑,我們看下具體實現(xiàn)代碼,如下:


private void addGetMethods(Class<?> clazz) {
  //conflictingGetters集合 key為屬性名稱腥寇,value為相應的getter方法集合鱼响,因為子類可能覆蓋父類的getter方法鸣剪,
  //所以同一屬性的名稱可能存在多個getter方法
  Map<String, List<Method>> conflictingGetters = new HashMap<>();
  //步驟一:獲取指定類以及父類和接口中定義的方法
  Method[] methods = getClassMethods(clazz);
  //步驟二:按照javabean規(guī)范查找getter方法 添加到conflictingGetters中
  Arrays.stream(methods).filter(m -> m.getParameterTypes().length == 0 && PropertyNamer.isGetter(m.getName()))
    .forEach(m -> addMethodConflict(conflictingGetters, PropertyNamer.methodToProperty(m.getName()), m));
  //對于getter方法進行處理
  resolveGetterConflicts(conflictingGetters);

Reflector.addFields()方法會處理類中定義的所有字段,并且將處理的字段信息添加到setMethods集合丈积、setTypes集合筐骇、getMethods集合、getTypes集合中江滨,Reflector.addFileds()方法的實現(xiàn)代碼如下:

//處理類中定義的所有字段
private void addFields(Class<?> clazz) {
  //提取clazz中定義的所有字段
  Field[] fields = clazz.getDeclaredFields();
  for (Field field : fields) {
    if (!setMethods.containsKey(field.getName())) {
      // issue #379 - removed the check for final because JDK 1.5 allows
      // modification of final fields through reflection (JSR-133). (JGB)
      // pr #16 - final static can only be set by the classloader
      int modifiers = field.getModifiers();
      //過濾調(diào)static和final修飾的方法
      if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) {
        //填充setMethods集合和setTypes集合
        addSetField(field);
      }
    }
    //getMethods集合中不包同名屬性時铛纬,將其記錄到getMethods集合和getTypes集合中
    if (!getMethods.containsKey(field.getName())) {
      //填充getMethods集合和getTypes集合
      addGetField(field);
    }
  }
  if (clazz.getSuperclass() != null) {
    //處理父類中定義的字段
    addFields(clazz.getSuperclass());
  }
}

Reflector中提供多個get *()方法用于讀取上述集合中的元數(shù)據(jù)信息。

3. Invoker & GetFieldInvoker & SetFieldInvoker & AmbiguousMethodInvoker & MethodInvoker

add *Methods()方法和add *Field()方法在上述集合中添加元素的時候唬滑,會將getter/setter方法對應的Method對象以及字段對應的Field對象統(tǒng)一封裝成Invoker對象告唆。Invoker接口的定義如下:


public interface Invoker {
  //調(diào)用指定字段的值或者指定的方法
  Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;

  //返回屬性相應的類型
  Class<?> getType();
}

invoker接口的實現(xiàn)如下圖:

<img src="http://qiniu-cdn.janker.top/oneblog/20200110135144701.jpg" style="zoom: 33%;" />

? GetFieldInvoker/SetFieldInvoker通過field字段封裝了FIeld對象,兩者的invoke()方法是通過調(diào)用Field.get()/set()方法實現(xiàn)的晶密。MethodInvoker通過method字段封裝了對應的Method對象擒悬,其invoke()方法是通過調(diào)用Method.invoke()方法實現(xiàn)的。

4. ReflectorFactory

ReflectorFactory接口主要實現(xiàn)了對Reflector對象的創(chuàng)建和緩存稻艰,接口定義如下:


public interface ReflectorFactory {

  //檢查該ReflectorFactory對象是否會緩存Reflector對象
  boolean isClassCacheEnabled();

  //設置是否緩存Reflector對象
  void setClassCacheEnabled(boolean classCacheEnabled);

  //創(chuàng)建指定對象的Reflector對象
  Reflector findForClass(Class<?> type);
}

MyBatis對ReflectorFactory接口只提供了DefaultReflectorFactory這一個實現(xiàn)類懂牧,他與Reflector關系如圖:

<img src="http://qiniu-cdn.janker.top/oneblog/20200110143413148.jpg" style="zoom:50%;" />

DefaultReflectorFactory的字段含義如下:

//該字段決定是否對Reflector對象的緩存
private boolean classCacheEnabled = true;
//使用ConcurrentHashMap集合實現(xiàn)對Reflector對象的緩存
private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<>();

DefaultReflectorFactory提供findForClass()方法實現(xiàn)為指定Class創(chuàng)建Reflector對象,并將Reflector對象緩存到reflectorMap集合中尊勿,具體代碼如下:

public Reflector findForClass(Class<?> type) {
  if (classCacheEnabled) { //檢測是否開啟緩存
   //cas放入緩存
   return reflectorMap.computeIfAbsent(type, Reflector::new);
  } else {
   //未開啟緩存則直接創(chuàng)建
   return new Reflector(type);
  }
}

此外除了使用MyBatis提供的DefaultReflectorFactory實現(xiàn)僧凤,們還可以在mybatis-config.xml中配置自定義的ReflectorFactory實現(xiàn)類,從而實現(xiàn)上面功能的拓展元扔。(后面會在介紹MyBatis初始化流程時躯保,會提到拓展點。)

5. TypeParameterResolver

1. Type知識準備

在分析TypeParameterResolver之前我們先來看下Type接口澎语,Type是所有類型的父接口途事,他有四個接口和一個實現(xiàn)類验懊,類圖如圖所示:

<img src="http://qiniu-cdn.janker.top/oneblog/20200110180942598.png" style="zoom:33%;" />

Class

Class:表示原始類型類型,Class對象表示JVM中一個類或者接口尸变,每個Java類在JVM都表現(xiàn)為一個Class對象鲁森。在程序中可以通過 ”xxx.class“,”對象.getClass()"或者是Class.forName("類名")來獲取Class對象。數(shù)組也被映射為Class對象振惰,所有元素類型相同切維數(shù)相同的數(shù)組都共享一個Class對象歌溉。

ParameterizedType

ParameterizedType:表示參數(shù)化類型,例如List< String >,Map<Integer,String>,Service< User >這種帶有泛型的類型骑晶。

GenericArrayType

GenericArrayType:表示的是數(shù)組類型且組成元素是ParameterizedType或者TypeVariable痛垛。例如List< String >[]或者T[]

TypeVariable

TypeVariable:表示的是類型變量,它用來反映在JVM編譯該泛型前的信息桶蛔。例如在LIst<T>中的T就是類型變量匙头,它在編譯的時候需要被轉化成一個具體的類型才能正常使用。

WildcardType

WildcardType:表示通配符類型仔雷,例如:? extends Number? extends Integer蹂析。

2. 方法解析

上面介紹了Type接口的基礎知識,我們回來繼續(xù)分析TypeParameterResolver碟婆。在對Reflector的分析中我們看到了TypeParameterResolver的身影电抚,他是一個工具類提供一些列靜態(tài)方法來解析指定類中的字段、方法返回值或者方法參數(shù)的類型竖共。TypeParameterResolver中各個方法之間的調(diào)用大致如下:【其中有一些遞歸調(diào)用沒有體現(xiàn)出來蝙叛,在后面的分析中會進行強調(diào)」】

<img src="http://qiniu-cdn.janker.top/oneblog/20200110184635768.png" style="zoom: 50%;" />

TypeParameterResolver中通過resolveFieldTypes()方法借帘、resolveReturnTypes()方法、resolveParamTypes()方法分別解析字段類型淌铐、方法返回值類型和方法參數(shù)列表中各個參數(shù)的類型肺然。這三個方法類似。我們就以resolveFieldTypes()來分析腿准。TypeParameterResolve.resolveFieldTypes()方法實現(xiàn)代碼如下:

public static Type resolveFieldType(Field field, Type srcType) {
  //獲取字段的聲明類型
  Type fieldType = field.getGenericType();
  //獲取字段定義所在類的Class對象
  Class<?> declaringClass = field.getDeclaringClass();
  //調(diào)用resolveType()方法做后續(xù)處理
  return resolveType(fieldType, srcType, declaringClass);
}

上述三個解析方法都會調(diào)用resolveType()會根據(jù)第一個參數(shù)Type际起,即方法、返回值或者方法返回參數(shù)的類型释涛,選擇合適的方法解析加叁。resolveType()的第二個參數(shù)表示查找該字段倦沧、返回值或者方法參數(shù)的起始位置唇撬。第三個參數(shù)則表示該字段、方法所在的類展融。

TypeParameterResolve.resolveType()方法代碼如下:

private static Type resolveType(Type type, Type srcType, Class<?> declaringClass) {
  if (type instanceof TypeVariable) {
    //解析 TypeVariable 類型
    return resolveTypeVar((TypeVariable<?>) type, srcType, declaringClass);
  } else if (type instanceof ParameterizedType) {
    //解析  ParameterizedType 類型
    return resolveParameterizedType((ParameterizedType) type, srcType, declaringClass);
  } else if (type instanceof GenericArrayType) {
    //解析  GenericArrayType 類型
    return resolveGenericArrayType((GenericArrayType) type, srcType, declaringClass);
  } else {
    return type;
  }
}

TypeParameterResolve.resolveParameterizedType()方法代碼如下:

private static ParameterizedType resolveParameterizedType(ParameterizedType parameterizedType, Type srcType, Class<?> declaringClass) {
  // 得到參數(shù)化類型中的原始類型對應的Class對象
  Class<?> rawType = (Class<?>) parameterizedType.getRawType();
  //返回參數(shù)化類型的類型變量
  Type[] typeArgs = parameterizedType.getActualTypeArguments();
  //用于保存解析后的結果
  Type[] args = new Type[typeArgs.length];
  for (int i = 0; i < typeArgs.length; i++) {
    if (typeArgs[i] instanceof TypeVariable) {
      //解析類型變量
      args[i] = resolveTypeVar((TypeVariable<?>) typeArgs[i], srcType, declaringClass);
    } else if (typeArgs[i] instanceof ParameterizedType) {
      //如果嵌套了ParameterizedType則調(diào)用resolveParameterizedType()方法進行處理
      args[i] = resolveParameterizedType((ParameterizedType) typeArgs[i], srcType, declaringClass);
    } else if (typeArgs[i] instanceof WildcardType) {
      //如果嵌套了WildcardType則調(diào)用resolveWildcardType()方法進行處理
      args[i] = resolveWildcardType((WildcardType) typeArgs[i], srcType, declaringClass);
    } else {
      args[i] = typeArgs[i];
    }
  }
  //將解析結果封裝成TypeParameterResolver中定義的ParameterizedType實現(xiàn)并返回
  return new ParameterizedTypeImpl(rawType, null, args);
}

TypeParameterResolve.resolveTypeVar()方法負責解析TypeVariable窖认。具體實現(xiàn)如下:


private static Type resolveTypeVar(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass) {
  Type result;
  Class<?> clazz;
  if (srcType instanceof Class) {
    clazz = (Class<?>) srcType;
  } else if (srcType instanceof ParameterizedType) {
    ParameterizedType parameterizedType = (ParameterizedType) srcType;
    clazz = (Class<?>) parameterizedType.getRawType();
  } else {
    throw new IllegalArgumentException("The 2nd arg must be Class or ParameterizedType, but was: " + srcType.getClass());
  }

  if (clazz == declaringClass) {
    //獲取上界
    Type[] bounds = typeVar.getBounds();
    if (bounds.length > 0) {
      return bounds[0];
    }
    return Object.class;
  }
  //獲取聲明的父類類型
  Type superclass = clazz.getGenericSuperclass();
  //通過掃描父類進行后續(xù)解析 這個是遞歸的入口
  result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superclass);
  if (result != null) {
    return result;
  }
  // 獲取接口
  Type[] superInterfaces = clazz.getGenericInterfaces();
  for (Type superInterface : superInterfaces) {
    //通過掃描接口進行后續(xù)解析 邏輯同掃描父類
    result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superInterface);
    if (result != null) {
      return result;
    }
  }
  //若在某個集成結構中解析成功則返回Object.class
  return Object.class;
}

scanSuperTypes()方法具體實現(xiàn)如下:

private static Type scanSuperTypes(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass, Class<?> clazz, Type superclass) {
  if (superclass instanceof ParameterizedType) {
    ParameterizedType parentAsType = (ParameterizedType) superclass;
    //獲取父類的原始類型
    Class<?> parentAsClass = (Class<?>) parentAsType.getRawType();
    TypeVariable<?>[] parentTypeVars = parentAsClass.getTypeParameters();
    if (srcType instanceof ParameterizedType) {
      //轉化父類參數(shù)化類型
      parentAsType = translateParentTypeVars((ParameterizedType) srcType, clazz, parentAsType);
    }
    if (declaringClass == parentAsClass) {
      for (int i = 0; i < parentTypeVars.length; i++) {
        if (typeVar.equals(parentTypeVars[i])) {
          return parentAsType.getActualTypeArguments()[i];
        }
      }
    }
    if (declaringClass.isAssignableFrom(parentAsClass)) {
      //繼續(xù)解析父類,知道解析到定義該字段的類
      return resolveTypeVar(typeVar, parentAsType, declaringClass);
    }
  } else if (superclass instanceof Class && declaringClass.isAssignableFrom((Class<?>) superclass)) {
    //聲明的父類不再含有類型變量且不是定義該字段的類則繼續(xù)解析
    return resolveTypeVar(typeVar, superclass, declaringClass);
  }
  return null;
}

分析完TypeParameterResolver.resolveTypeVar()和resolveParameterizedType()兩個方法后,再來看resolveGenericArrayType()方法扑浸,該方法負責解析GenericArrayType類型的變量烧给,它會根據(jù)數(shù)組元素的類型選擇合適的resolve *()方法進行解析,具體實現(xiàn)如下:

private static Type resolveGenericArrayType(GenericArrayType genericArrayType, Type srcType, Class<?> declaringClass) {
  //獲取數(shù)組元素的類型
  Type componentType = genericArrayType.getGenericComponentType();
  Type resolvedComponentType = null;
  //根據(jù)數(shù)組元素類型選擇合適的方法進行解析
  if (componentType instanceof TypeVariable) {
    resolvedComponentType = resolveTypeVar((TypeVariable<?>) componentType, srcType, declaringClass);
  } else if (componentType instanceof GenericArrayType) {
    //遞歸調(diào)用resolveGenericArrayType()方法
    resolvedComponentType = resolveGenericArrayType((GenericArrayType) componentType, srcType, declaringClass);
  } else if (componentType instanceof ParameterizedType) {
    resolvedComponentType = resolveParameterizedType((ParameterizedType) componentType, srcType, declaringClass);
  }
  //根絕解析后的數(shù)組項類型構造返回類型
  if (resolvedComponentType instanceof Class) {
    return Array.newInstance((Class<?>) resolvedComponentType, 0).getClass();
  } else {
    return new GenericArrayTypeImpl(resolvedComponentType);
  }
}

最后我們來分析一下TypeParameterResolver.resolveWildcardType()方法喝噪。該方法負責解析WildcardType類型的變量础嫡。首先解析WildcardType類型的上下界,然后通過解析后的結果構造WildcardTypeImpl對象返回酝惧。具體解析過程與上述resolve *()類似榴鼎。

通過上面的方法分析我們知道,當存在復雜的繼承關系以及泛型類型時晚唇,TypeParameterResolver可以幫助我們解析字段巫财、方法和方法返回值的類型。這個是Reflector類的基礎哩陕。

MyBatis源碼中也提供了TypeParameterResolver相關的TypeParameterResolverTest這個測試類平项,可以從多方面測試TypeParameterResolver的功能。我們可以參考一下更好的了解TypeParameterResolver的功能悍及。

6. ObjectFactory

MyBatis中有很多模塊會使用到ObjectFactory這個接口闽瓢,該接口提供了多個crate()方法的重載,通過這些方法可以創(chuàng)建指定類型的對象心赶。ObjectFactory接口定義如下:

public interface ObjectFactory {
  //設置配置信息
  default void setProperties(Properties properties) {
    // NOP
  }
  //通過無參構造器創(chuàng)建指定類的對象
  <T> T create(Class<T> type);
  //根據(jù)參數(shù)列表鸳粉,從指定類型中選擇合適的構造器創(chuàng)建對象
  <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);
  //檢測指定類型是否為集合類型,主要處理java.util.Collection及其子類
  <T> boolean isCollection(Class<T> type);
}

DefaultObjectFactory是MyBatis提供的ObjectFactory接口的唯一實現(xiàn)园担,它是一個反射工廠届谈,其create()方法通過調(diào)用instantiateClass()方法實現(xiàn)。DefaultObjectFactory.instantiateClass()方法會根據(jù)傳入的參數(shù)列表選擇合適的構造函數(shù)實例化對象弯汰,具體實現(xiàn)如下:

private  <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
  try {
    Constructor<T> constructor;
    //通過無參構造函數(shù)創(chuàng)建對象
    if (constructorArgTypes == null || constructorArgs == null) {
      constructor = type.getDeclaredConstructor();
      try {
        return constructor.newInstance();
      } catch (IllegalAccessException e) {
        if (Reflector.canControlMemberAccessible()) {
          constructor.setAccessible(true);
          return constructor.newInstance();
        } else {
          throw e;
        }
      }
    }
    //根據(jù)指定的參數(shù)列好查找構造函數(shù)艰山,并實例化對象
    constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[0]));
    try {
      return constructor.newInstance(constructorArgs.toArray(new Object[0]));
    } catch (IllegalAccessException e) {
      if (Reflector.canControlMemberAccessible()) {
        constructor.setAccessible(true);
        return constructor.newInstance(constructorArgs.toArray(new Object[0]));
      } else {
        throw e;
      }
    }
  } catch (Exception e) {
    String argTypes = Optional.ofNullable(constructorArgTypes).orElseGet(Collections::emptyList)
        .stream().map(Class::getSimpleName).collect(Collectors.joining(","));
    String argValues = Optional.ofNullable(constructorArgs).orElseGet(Collections::emptyList)
        .stream().map(String::valueOf).collect(Collectors.joining(","));
    throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
  }
}

除了使用MyBatis提供的DefaultObjectFactory實現(xiàn),我們還可以在mybatis-config.xml配置文件中指定自定義的ObjectFactory接口實現(xiàn)類咏闪,從而實現(xiàn)功能上的拓展曙搬。

7. Property工具集

下面我們介紹反射模塊使用到的三個屬性工具類,分別是PropertyTokenizer鸽嫂、PropertyNamerPropertyCopier纵装。

PropertyTokenizer

PropertyTokenizer中各個字段含義如下:

//當前表達式的名稱
private String name;
//當前表達式的索引名
private final String indexedName;
//索引下標
private String index;
//子表達式
private final String children;

在PropertyTokenizer的構造函數(shù)中會對傳入的表達式進行分析,并初始化上面的屬性字段据某,實現(xiàn)如下:

public PropertyTokenizer(String fullname) {
  //查找"."的位置
  int delim = fullname.indexOf('.');
  if (delim > -1) {
    //初始化name
    name = fullname.substring(0, delim);
    //初始化children
    children = fullname.substring(delim + 1);
  } else {
    name = fullname;
    children = null;
  }
  //初始化indexedName
  indexedName = name;
  delim = name.indexOf('[');
  if (delim > -1) {
    //初始化index
    index = name.substring(delim + 1, name.length() - 1);
    name = name.substring(0, delim);
  }
}

PropertyTokenizer繼承了Iterator接口橡娄,它可以迭代處理嵌套多層表達式。PropertyTokenizer.next()會創(chuàng)建新的PropertyTokenizer對象并解析children字段記錄的子表達式癣籽。

PropertyNamer

PropertyNamer是另一個工具類挽唉,將提供了下列靜態(tài)方法幫助完成方法名到屬性名的轉換滤祖,以及多種檢測操作。

public final class PropertyNamer {

  private PropertyNamer() {
    // Prevent Instantiation of Static Class
  }

  //該方法會將方法名轉換成屬性
  public static String methodToProperty(String name) {
    if (name.startsWith("is")) {
      name = name.substring(2);
    } else if (name.startsWith("get") || name.startsWith("set")) {
      name = name.substring(3);
    } else {
      throw new ReflectionException("Error parsing property name '" + name + "'.  Didn't start with 'is', 'get' or 'set'.");
    }

    if (name.length() == 1 || (name.length() > 1 && !Character.isUpperCase(name.charAt(1)))) {
      name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
    }

    return name;
  }

  // 檢測是否是對應屬性名
  public static boolean isProperty(String name) {
    return isGetter(name) || isSetter(name);
  }

  //檢測是否為getter方法
  public static boolean isGetter(String name) {
    return (name.startsWith("get") && name.length() > 3) || (name.startsWith("is") && name.length() > 2);
  }

  //檢測是否為setter方法
  public static boolean isSetter(String name) {
    return name.startsWith("set") && name.length() > 3;
  }
}

PropertyCopier

PropertyCopier是一個屬性拷貝的工具類瓶籽。其核心方法是copyBeanProperties()方法匠童,主要實現(xiàn)相同類型的兩個對象之間的屬性拷貝,具體實現(xiàn)如下:

public static void copyBeanProperties(Class<?> type, Object sourceBean, Object destinationBean) {
  Class<?> parent = type;
  while (parent != null) {
    final Field[] fields = parent.getDeclaredFields();
    for (Field field : fields) {
      try {
        try {
          field.set(destinationBean, field.get(sourceBean));
        } catch (IllegalAccessException e) {
          if (Reflector.canControlMemberAccessible()) {
            field.setAccessible(true);
            //將sourceBean對象中的屬性設置到destinationBean對象中
            field.set(destinationBean, field.get(sourceBean));
          } else {
            throw e;
          }
        }
      } catch (Exception e) {
        // Nothing useful to do, will only fail on final fields, which will be ignored.
      }
    }
    // 繼續(xù)拷貝父類中的定義的字段
    parent = parent.getSuperclass();
  }
}

8. MetaClass

MetaClass通過Reflector和PropertyTokenizer組合使用塑顺,實現(xiàn)了對復雜的屬性表達式的解析汤求,并實現(xiàn)了獲取指定屬性信息的功能。MetaClass中各個字段的含義如下:

//用于緩存Reflector對象
private final ReflectorFactory reflectorFactory;
//在創(chuàng)建MetaClasyos時會指定一個類严拒,該Reflector對象會用于記錄該類相關的元數(shù)據(jù)
private final Reflector reflector;

MetaClass的構造函數(shù)會為指定的Class創(chuàng)建對應的Reflector對象首昔,并用其初始化MetaClass.reflector字段,具體代碼如下:

//MetaClass的構造方法是使用private修飾的
private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
  this.reflectorFactory = reflectorFactory;
  //創(chuàng)建Reflector對象
  this.reflector = reflectorFactory.findForClass(type);
}

//使用靜態(tài)方法創(chuàng)建MetaClass對象
public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) {
  return new MetaClass(type, reflectorFactory);
}

MetaClass中比較重要的是findProperty()方法糙俗,他是通過MetaClass.buildProperty()方法實現(xiàn)的勒奇,而buildProperty()方法會通過PropertyTokenizer解析更復雜的屬性表達式,具體實現(xiàn)如下:

public String findProperty(String name) {
  //委托給buildProperty()方法實現(xiàn)
  StringBuilder prop = buildProperty(name, new StringBuilder());
  return prop.length() > 0 ? prop.toString() : null;
}
private StringBuilder buildProperty(String name, StringBuilder builder) {
    //解析屬性表達式
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) { //是否有子表達式
      //查找PropertyTokenizer.name對應的屬性
      String propertyName = reflector.findPropertyName(prop.getName());
      if (propertyName != null) {
        //追加屬性名
        builder.append(propertyName);
        builder.append(".");
        //為該屬性創(chuàng)建MataClass對象
        MetaClass metaProp = metaClassForProperty(propertyName);
        //遞歸解析PropertyTokenizer.children字段巧骚,并將解析結果添加到builder中保存
        metaProp.buildProperty(prop.getChildren(), builder);
      }
    } else {
      //遞歸出口
      String propertyName = reflector.findPropertyName(name);
      if (propertyName != null) {
        builder.append(propertyName);
      }
    }
    return builder;
 }
 public MetaClass metaClassForProperty(String name) {
    //查找指定屬性對應的class
    Class<?> propType = reflector.getGetterType(name);
    //為改屬性創(chuàng)建對應的MetaClass對象
    return MetaClass.forClass(propType, reflectorFactory);
 }

注意:Meta.Class.findProperty()方法只查找"."導航的屬性赊颠,并沒有檢測下標。

MetaClass.hasGetter()方法和MetaClass.hasSetter()方法負責判斷屬性表達式所表示的屬性是否有對應的屬性劈彪,這兩個方法邏輯類似竣蹦,我們以hasGetter()方法為例子進行分析,這兩個類方法實現(xiàn)最終都會查找Reflector.getMethods集合或Reflector.setMethods集合沧奴。根據(jù)前面介紹的Reflector.addFields()方法痘括,當字段沒有對應的getter/setter方法時會添加相應的getFieldInvoker/setFieldInvoker對象,所以Reflector有權限訪問指定字段的時候這兩個方法的行為并不像其方法所暗示的那樣只直接判斷屬性的getter/setter方法滔吠,我們來看看MetaClass.hasGetter()方法的實現(xiàn)代碼:

public boolean hasGetter(String name) {
  //解析屬性表達式
  PropertyTokenizer prop = new PropertyTokenizer(name);
  //存在待處理的子表達式
  if (prop.hasNext()) {
    //PropertyTokenizer.name指定的屬性有getter方法 才能處理子表達式
    if (reflector.hasGetter(prop.getName())) {
      //metaClassForProperty(PropertyTokenizer)是上面metaClassForProperty(String)的重載 但是邏輯有很大差異
      MetaClass metaProp = metaClassForProperty(prop);
      //遞歸入口
      return metaProp.hasGetter(prop.getChildren());
    } else {
      //遞歸出口
      return false;
    }
  } else {
    //遞歸出口
    return reflector.hasGetter(prop.getName());
  }
}

MetaClass.metaClassForProperty(PropertyTokenizer)方法底層會調(diào)用MetaClass.getGetterType(PropertyTokenizer)方法纲菌,針對PropertyTokenizer中是否包含索引信息進一步處理,代碼如下:

private MetaClass metaClassForProperty(PropertyTokenizer prop) {
  //獲取表達式標識的屬性的類型
  Class<?> propType = getGetterType(prop);
  return MetaClass.forClass(propType, reflectorFactory);
}

private Class<?> getGetterType(PropertyTokenizer prop) {
  //獲取屬性類型
  Class<?> type = reflector.getGetterType(prop.getName());
  //該表達式中是否試用"[]"指定了下標疮绷,切是Collect子類
  if (prop.getIndex() != null && Collection.class.isAssignableFrom(type)) {
    //通過TypeParameterResolver工具類解析屬性的類型
    Type returnType = getGenericGetterType(prop.getName());
    //針對ParameterizedType進行處理翰舌,既針對泛型類型進行處理
    if (returnType instanceof ParameterizedType) {
      //獲取實際的類型參數(shù)
      Type[] actualTypeArguments = ((ParameterizedType) returnType).getActualTypeArguments();
      if (actualTypeArguments != null && actualTypeArguments.length == 1) {
        //泛型的類型
        returnType = actualTypeArguments[0];
        if (returnType instanceof Class) {
          type = (Class<?>) returnType;
        } else if (returnType instanceof ParameterizedType) {
          type = (Class<?>) ((ParameterizedType) returnType).getRawType();
        }
      }
    }
  }
  return type;
}

private Type getGenericGetterType(String propertyName) {
  try {
    //根據(jù)Reflector.getMethods集合中記錄的invoker實現(xiàn)類的類型,決定解析getter方法返回值類型還是解析字段類型
    Invoker invoker = reflector.getGetInvoker(propertyName);
    if (invoker instanceof MethodInvoker) {
      Field _method = MethodInvoker.class.getDeclaredField("method");
      _method.setAccessible(true);
      Method method = (Method) _method.get(invoker);
      return TypeParameterResolver.resolveReturnType(method, reflector.getType());
    } else if (invoker instanceof GetFieldInvoker) {
      Field _field = GetFieldInvoker.class.getDeclaredField("field");
      _field.setAccessible(true);
      Field field = (Field) _field.get(invoker);
      return TypeParameterResolver.resolveFieldType(field, reflector.getType());
    }
  } catch (NoSuchFieldException | IllegalAccessException ignored) {
  }
  return null;
}

MetaClass中的其他get *()方法比較簡單冬骚,大多數(shù)直接依賴Reflector的對應方法的實現(xiàn)的椅贱。通過對MetaClass的分析,我們了解了findProperty()只冻、hasGetter()庇麦、hasSetter()等方法的實現(xiàn)原理。

9. ObjectWrapper

ObjectWrapper顧名思義就是對象的包裝類喜德,對對象級別的元信息進行處理山橄。ObjectWrapper接口是對對象的包裝,抽象了對象的屬性信息住诸,它定義了一系列的查詢對屬性信息的方法驾胆,以及更新屬性的方法。

ObjectWrapper接口的定義如下:

public interface ObjectWrapper {
  //如果是普通bean調(diào)用getter方法 如果是集合 則獲取指定key或者下標對應的value值
  Object get(PropertyTokenizer prop);
  //如果是普通bean調(diào)用setter方法 如果是集合 則設置指定key或者下標對應的value值
  void set(PropertyTokenizer prop, Object value);
  //查找屬性表達式指定的屬性贱呐,第二個參數(shù)標識是否忽視屬性表達式的下劃線
  String findProperty(String name, boolean useCamelCaseMapping);

  //查找可讀屬性的名稱集合
  String[] getGetterNames();
  //查找可寫屬性的名稱集合
  String[] getSetterNames();

  //解析表達式指定屬性的setter方法的參數(shù)類型
  Class<?> getSetterType(String name);
  //解析表達式指定屬性的getter方法的參數(shù)類型
  Class<?> getGetterType(String name);

  //判斷屬性表達式指定屬性是否有getter方法
  boolean hasSetter(String name);
  //判斷屬性表達式指定屬性是否有setter方法
  boolean hasGetter(String name);

  //為屬性表達式指定的屬性創(chuàng)建相應的MetaObject對象
  MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory);

  //封裝的對象是否為Collect類型
  boolean isCollection();

  //調(diào)用Collection對象的add()方法
  void add(Object element);
  //調(diào)用Collection對象的addAll()方法
  <E> void addAll(List<E> element);
}

ObjectWrapperFactory負責創(chuàng)建ObjectWrapper對象丧诺,關系如圖所示:

<img src="http://qiniu-cdn.janker.top/oneblog/20200111223939490.jpg" style="zoom:67%;" />

DefaultObjectWrapperFactory實現(xiàn)了ObjectWrapperFactory接口,但它實現(xiàn)的getWrapperFor()方法始終拋出異常奄薇,hasWrapperFor()方法始終返回false驳阎,所以該實現(xiàn)方法實際上是不可用的。但是與ObjectFactory類似馁蒂,我們可以在mybatis-config.xml配置自定義的ObjectWrapperFactory實現(xiàn)類進行拓展呵晚。

BaseWrapper是一個實現(xiàn)了ObjectWrapper接口的抽象類,其中封裝了MetaObject對象沫屡,并提供了三個常用的方法供其子類使用饵隙。如圖所示:

<img src="http://qiniu-cdn.janker.top/oneblog/20200111225050400.jpg" style="zoom:50%;" />

BaseWrapper.resolveCollection()方法會調(diào)用MetaObject.getValue()方法,它會解析屬性表達式并獲取指定的屬性沮脖,MetaObject.getValue()方法的實現(xiàn)在下面介紹金矛。

BaseWrapper.getCollectionValue()方法和setCollectionValue()方法會解析屬性表達式的索引信息,然后獲取或設置對應項勺届。這兩個方法類似驶俊。在這里我們只分析一下getCollectionValue()方法。

protected Object getCollectionValue(PropertyTokenizer prop, Object collection) {
  if (collection instanceof Map) {
    //如果是map類型則index為key
    return ((Map) collection).get(prop.getIndex());
  } else {
    //如果是其他類型則index為下標
    int i = Integer.parseInt(prop.getIndex());
    if (collection instanceof List) {
      return ((List) collection).get(i);
    } else if (collection instanceof Object[]) {
      return ((Object[]) collection)[i];
    } else if (collection instanceof char[]) {
      return ((char[]) collection)[i];
    } else if (collection instanceof boolean[]) {
      return ((boolean[]) collection)[i];
    } else if (collection instanceof byte[]) {
      return ((byte[]) collection)[i];
    } else if (collection instanceof double[]) {
      return ((double[]) collection)[i];
    } else if (collection instanceof float[]) {
      return ((float[]) collection)[i];
    } else if (collection instanceof int[]) {
      return ((int[]) collection)[i];
    } else if (collection instanceof long[]) {
      return ((long[]) collection)[i];
    } else if (collection instanceof short[]) {
      return ((short[]) collection)[i];
    } else {
      throw new ReflectionException("The '" + prop.getName() + "' property of " + collection + " is not a List or Array.");
    }
  }
}

BeanWrapper繼承了BaseWrapper抽象類免姿,其中封裝了一個JavaBean對象以及該JavaBean相應的MetaClass對象饼酿,當然還有從BaseWrapper繼承下來的、該JavaBean對象相應的MetaObject對象胚膊。

BeanWrapper.get()方法和set()方法會根據(jù)指定的屬性表達式故俐,獲取或者設置相應的屬性值,兩者邏輯相似紊婉,這里我們以get()方法分析购披,具體代碼如下:

public Object get(PropertyTokenizer prop) {
  //存在索引信息 則表示屬性表達式中的name部分為集合類型
  if (prop.getIndex() != null) {
    //通過MetaObject.getValue()方法獲取object對象中指定集合屬性
    Object collection = resolveCollection(prop, object);
    //獲取集合元素
    return getCollectionValue(prop, collection);
  } else {
    //不存在索引信息 則name部分為普通對象,查找并調(diào)用invoker相關方法獲取屬性
    return getBeanProperty(prop, object);
  }
}
private Object getBeanProperty(PropertyTokenizer prop, Object object) {
    try {
      //根據(jù)屬性名稱查找Reflector.getMethods集合中相應的getFieldInvoker或者MethodInvoker
      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);
    }
  }

CollectionWrapper實現(xiàn)了ObjectWrapper接口肩榕,其中封裝了Collection< Object >類型的對象刚陡,但是它大部分實現(xiàn)方法都會拋出UnsupportedOperationException異常。

MapWrapper是BaseWrapper的另一個實現(xiàn)類株汉,其中封裝了Map<String,Object>類型對象筐乳,我們了解了MetaObject和BeanWrapper實現(xiàn)后,輕而易舉就能看懂MapWrapper的實現(xiàn)代碼乔妈。

10. MetaObject

MetaObject提供了獲取/設置對象中指定的屬性值蝙云、檢測getter/setter等常用功能,但是ObjectWrapper只是這些功能的最后一站路召,我們省略了對屬性表達式解析過程的介紹勃刨,而該解析過程就是在MetaObject中實現(xiàn)的波材。

MetaObject中字段的含義如下:

//原始JavaBean對象
private final Object originalObject;
//封裝了originalObject對象
private final ObjectWrapper objectWrapper;
//負責實例化originalObject的工廠對象
private final ObjectFactory objectFactory;
//負責創(chuàng)建ObjectWrapper的工廠對象
private final ObjectWrapperFactory objectWrapperFactory;
//用于創(chuàng)建并緩存Reflector對象的工廠對象
private final ReflectorFactory reflectorFactory;

MetaObject的構造方法會根據(jù)傳入的原始對象的類型以及ObjectFactory工廠的實現(xiàn)創(chuàng)建相應的ObjectWrapper對象,代碼如下:

private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
  //初始化上述字段
  this.originalObject = object;
  this.objectFactory = objectFactory;
  this.objectWrapperFactory = objectWrapperFactory;
  this.reflectorFactory = reflectorFactory;

  //若原始對象已經(jīng)是ObjectWrapper對象則直接使用
  if (object instanceof ObjectWrapper) {
    this.objectWrapper = (ObjectWrapper) object;
  } else if (objectWrapperFactory.hasWrapperFor(object)) {
    //若objectWrapperFactory能夠為該原始兌現(xiàn)創(chuàng)建對應的ObjectWrapper對象則由優(yōu)先使用objectWrapperFactory身隐,
    //而DefaultObjectWrapperFactory.hasWrapperFor()始終返回false,用戶可以自定義ObjectWrapperFactory實現(xiàn)進行拓展
    this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
  } else if (object instanceof Map) {
    //若原始對象是map類型 則創(chuàng)建MapWrapper對象
    this.objectWrapper = new MapWrapper(this, (Map) object);
  } else if (object instanceof Collection) {
    //若原始對象是Collection類型 則創(chuàng)建CollectionWrapper對象
    this.objectWrapper = new CollectionWrapper(this, (Collection) object);
  } else {
    //若對象是普通的JavaBean對象廷区,則創(chuàng)建BeanWrapper對象
    this.objectWrapper = new BeanWrapper(this, object);
  }
}
//Meta的構造方法是private的 只能靠forObject()這個靜態(tài)方法來創(chuàng)建MetaObject對象
public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
    if (object == null) {
      //若原始對象為空 則統(tǒng)一返回SystemMetaObject.NULL_META_OBJECT這個靜態(tài)對象
      return SystemMetaObject.NULL_META_OBJECT;
    } else {
      return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
    }
  }

MetaObject和ObjectWrapper中關于類級別的方法,例如hasGetter()贾铝、hasSetter()隙轻、findProperty()等方法,都是直接調(diào)用MetaClass的對應方法實現(xiàn)的垢揩。其他方法都是關于對象級別的方法玖绿,這些方法都是與ObjectWrapper配合實現(xiàn),例如MetaObject.getValue()/setValue()方法叁巨,這里以getValue()方法為例進行分析斑匪,具體代碼如下:

public Object getValue(String name) {
  //解析屬性表達式
  PropertyTokenizer prop = new PropertyTokenizer(name);
  if (prop.hasNext()) { //處理子表達式
    //根據(jù)PropertyTokenizer解析后制定的屬性 創(chuàng)建相應的MetaObject對象
    MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
    if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
      return null;
    } else {
      //遞歸處理子表達式
      return metaValue.getValue(prop.getChildren());
    }
  } else {
    //通過ObjectWrapper獲取指定的屬性值
    return objectWrapper.get(prop);
  }
}
public MetaObject metaObjectForProperty(String name) {
    //獲取指定的屬性
    Object value = getValue(name);
    //創(chuàng)建該屬性對象相應的MetaObject對象
    return MetaObject.forObject(value, objectFactory, objectWrapperFactory, reflectorFactory);
  }

ObjectWrapper.instantiateProperty()方法實際上就是調(diào)用ObjectFactory接口的create()方法(默認實現(xiàn)是DefaultObjectFactory)創(chuàng)建對象并將其設置到所屬的對象中,這里我們看下具體的實現(xiàn)代碼:

public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {
  MetaObject metaValue;
  //獲取屬性相應的setter方法的參數(shù)類型
  Class<?> type = getSetterType(prop.getName());
  try {
    //通過反射的方式創(chuàng)建對象
    Object newObject = objectFactory.create(type);
    metaValue = MetaObject.forObject(newObject, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory(), metaObject.getReflectorFactory());
    //將上面創(chuàng)建的屬性對象 設置到對應的屬性對象集合中
    set(prop, newObject);
  } catch (Exception e) {
    throw new ReflectionException("Cannot set value of property '" + name + "' because '" + name + "' is null and cannot be instantiated on instance of " + type.getName() + ". Cause:" + e.toString(), e);
  }
  return metaValue;
}

理解了MetaObject和BeanWrapper如何通過遞歸的方式處理屬性表達式指定的屬性值后锋勺,其他方法的實現(xiàn)原理就好理解了秤标。例如getGetterType()、getSetterType()宙刘、hasGetter()苍姜、hasSetter()等方法,都是先遞歸處理屬性表達式悬包,然后調(diào)用MetaClass相應的方法實現(xiàn)的衙猪。

本文由 Janker 創(chuàng)作,采用 CC BY 3.0 CN協(xié)議 進行許可布近。 可自由轉載垫释、引用,但需署名作者且注明文章出處撑瞧。如轉載至微信公眾號棵譬,請在文末添加作者公眾號二維碼。
<img src="http://qiniu-cdn.janker.top/oneblog/20200311150833864.jpg" style="zoom:50%;" />

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末预伺,一起剝皮案震驚了整個濱河市订咸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌酬诀,老刑警劉巖脏嚷,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異瞒御,居然都是意外死亡父叙,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來趾唱,“玉大人涌乳,你說我怎么就攤上這事√瘃” “怎么了夕晓?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長带欢。 經(jīng)常有香客問我运授,道長烤惊,這世上最難降的妖魔是什么乔煞? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮柒室,結果婚禮上渡贾,老公的妹妹穿的比我還像新娘。我一直安慰自己雄右,他們只是感情好空骚,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著擂仍,像睡著了一般囤屹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上逢渔,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天肋坚,我揣著相機與錄音,去河邊找鬼肃廓。 笑死智厌,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的盲赊。 我是一名探鬼主播铣鹏,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼哀蘑!你這毒婦竟也來了诚卸?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤绘迁,失蹤者是張志新(化名)和其女友劉穎惨险,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體脊髓,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡辫愉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了将硝。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恭朗。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡屏镊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出痰腮,到底是詐尸還是另有隱情而芥,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布膀值,位于F島的核電站棍丐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏沧踏。R本人自食惡果不足惜歌逢,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望翘狱。 院中可真熱鬧秘案,春花似錦、人聲如沸潦匈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茬缩。三九已至赤惊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間凰锡,已是汗流浹背未舟。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留寡夹,地道東北人处面。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像菩掏,于是被迫代替她去往敵國和親魂角。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容