mybatis 反射工具箱

mybatis封裝了本身的反射類工具箱。java

Reflector類中:數組

構造方法以下:解析指定class隊形,填充以下集合緩存

public Reflector(Class<?> clazz) {
  type = clazz;//初始化clazz字段
  addDefaultConstructor(clazz);//查找clazz默認構造方法
  addGetMethods(clazz);//處理clazz中getter方法,填充getMethods集合和getTypes集合
  addSetMethods(clazz);//處理clazz中setter方法,填充setMethods集合和setTypes集合
  addFields(clazz);//處理無setter/getter方法的字段
  //根據getMethods/setMethods集合,初始化可讀/寫屬性的名稱集合
  readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]);
  writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]);
  for (String propName : readablePropertyNames) {//初始化caseInsensitivePropertyMap(記錄了全部屬性名稱)集合,其中記錄了全部大寫格式屬性名稱
    caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
  }
  for (String propName : writeablePropertyNames) {
    caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
  }
}

調用了安全

private void addDefaultConstructor(Class<?> clazz) {
  Constructor<?>[] consts = clazz.getDeclaredConstructors();//獲取構造方法的參數類型
  for (Constructor<?> constructor : consts) {
    if (constructor.getParameterTypes().length == 0) {//若爲無參構造函數(默認構造函數)
      if (canAccessPrivateMethods()) {//安全管理器已作檢查經過則返回ture不然拋出異常返回false
        try {
          constructor.setAccessible(true);//將 accessible 標誌設置爲指示的布爾值,值爲 true 則指示反射的對象在使用時應該取消 Java 語言訪問檢查,從而提升了性能。值爲 false 則指示反射的對象應該實施 Java 語言訪問檢查。
        } catch (Exception e) {
          // Ignored. This is only a final precaution, nothing we can do.
            忽略。 這只是最後的預防措施,咱們作不了什麼。
        }
      }
      if (constructor.isAccessible()) {//獲取上面的Accessible的flag值(true或者false)
        this.defaultConstructor = constructor;
      }
    }
  }
}

addGetMethods()解析類中定義的getter方法mybatis

先調用getClassMethods,以下所示,接着app

private Method[] getClassMethods(Class<?> cls) {//該方法獲取當前類及父類中定義的全部方法的惟一簽名和對應Method對象
//用於記錄指定類中定義的所有方法的惟一簽名及對應Method對象  
Map<String, Method> uniqueMethods = new HashMap<String, Method>();
  Class<?> currentClass = cls;
  while (currentClass != null) {
    //記錄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());
    }

    currentClass = currentClass.getSuperclass();//獲取父類繼續循環
  }

  Collection<Method> methods = uniqueMethods.values();

  return methods.toArray(new Method[methods.size()]);//轉成methods數組返回
}
//返回值類型#方法名稱:參數類型列表。例如:Reflector.getSignature(Method)方法惟一簽名是:java.lang.String#getSignature:java.lang.reflect.Method
private String getSignature(Method method) {
  StringBuilder sb = new StringBuilder();
  //該對象返回值類型
  Class<?> returnType = method.getReturnType();
  if (returnType != null) {
    sb.append(returnType.getName()).append('#');
  }
  sb.append(method.getName());
  //該對象表示的方法的參數類型
  Class<?>[] parameters = method.getParameterTypes();
  for (int i = 0; i < parameters.length; i++) {
    if (i == 0) {
      sb.append(':');
    } else {
      sb.append(',');
    }
    sb.append(parameters[i].getName());
  }
  return sb.toString();
}
private void addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods) {//爲每一個方法生成惟一簽名,記錄到uniqueMethods集合中
  for (Method currentMethod : methods) {
    if (!currentMethod.isBridge()) {//橋接方法,JDK 1.5 引入泛型後,爲了使Java的泛型方法生成的字節碼和 1.5 版本前的字節碼相兼容,由編譯器自動生成的方法
      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
      //檢測是否在子類中已經添加了這個方法,若添加過,則表示子類覆寫了這個方法,則不用再向uniqueMethods集合中添加這個方法了
      if (!uniqueMethods.containsKey(signature)) {
        if (canAccessPrivateMethods()) {//安全管理器已作檢查經過則返回ture不然拋出異常返回false
          try {
            currentMethod.setAccessible(true);//將 accessible 標誌設置爲指示的布爾值,值爲 true 則指示反射的對象在使用時應該取消 Java 語言訪問檢查,從而提升了性能。值爲 false 則指示反射的對象應該實施 Java 語言訪問檢查。
          } catch (Exception e) {
            // Ignored. This is only a final precaution, nothing we can do.
           //忽略。 這只是最後的預防措施,咱們作不了什麼
          }
        }
        //記錄該簽名和方法的對應關係
        uniqueMethods.put(signature, currentMethod);
      }
    }
  }
}
/** 解決衝突 */
private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {
    for (Entry<String, List<Method>> 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();

            /* 
             * 兩個方法的返回值類型一致,若兩個方法返回值類型均爲 boolean,則選取 isXXX 方法
             * 爲 winner。不然沒法決定哪一個方法更爲合適,只能拋出異常
             */
            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.");

                /*
                 * 若是方法返回值類型爲 boolean,且方法名以 "is" 開頭,
                 * 則認爲候選方法 candidate 更爲合適
                 */
                } else if (candidate.getName().startsWith("is")) {
                    winner = candidate;
                }

            /*
             * winnerType 是 candidateType 的子類,類型上更爲具體,
             * 則認爲當前的 winner 還是合適的,無需作什麼事情
             */
            } else if (candidateType.isAssignableFrom(winnerType)) {

            /*
             * candidateType 是 winnerType 的子類,此時認爲 candidate 方法更爲合適,
             * 故將 winner 更新爲 candidate
             */
            } 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.");
            }
        }

        // 將篩選出的方法添加到 getMethods 中,並將方法返回值添加到 getTypes 中
        addGetMethod(propName, winner);
    }
}
private void addGetMethod(String name, Method method) {
  if (isValidPropertyName(name)) {//檢測屬性名是否合法,即屬性名不能以'$'開頭且不能等於'class','serialVersionUID'
    getMethods.put(name, new MethodInvoker(method));//將屬性名及對應MethodInvoker對象添加到getMethods集合中
    Type returnType = TypeParameterResolver.resolveReturnType(method, type);//獲取返回值type
    getTypes.put(name, typeToClass(returnType));//將屬性名及getter方法返回值類型添加到getTypes集合中保存
  }
}
private void addGetMethods(Class<?> cls) {
  Map<String, List<Method>> conflictingGetters = new HashMap<String, List<Method>>();
  //conflictingGetters 集合key是屬性名,value是getter方法集合,因爲子類可能覆寫父類getter方法,因此同一屬性名會有多個getter方法
  Method[] methods = getClassMethods(cls);//獲取制定類及父類和接口中定義的方法
  for (Method method : methods) {//
    if (method.getParameterTypes().length > 0) {
      continue;
    }
    String name = method.getName();
    //javaBean中getter方法的方法名長度以"get"開頭而且長度大於3或者以"is"開頭而且長度大於2    
    if ((name.startsWith("get") && name.length() > 3)
        || (name.startsWith("is") && name.length() > 2)) {
      name = PropertyNamer.methodToProperty(name);//截取掉get或者is獲取後面實際的對應屬性名稱
      addMethodConflict(conflictingGetters, name, method);//若此方法在conflictingGetters中沒有,則放入key是屬性名 和value 是getter方法集合不然只放入list集合中的方法
    }
  }
  resolveGetterConflicts(conflictingGetters);//調用上面解決衝突的方法
}
private void addFields(Class<?> clazz) {//處理類中定義全部字段,並在處理後添加到setMethods集合,setTypes集合,getMethods集合以及getTypes集合中
  Field[] fields = clazz.getDeclaredFields();//獲取clazz中定義的全部字段
  for (Field field : fields) {
    if (canAccessPrivateMethods()) {//安全管理器已作檢查經過則返回ture不然拋出異常返回false
      try {
        field.setAccessible(true);//將 accessible 標誌設置爲指示的布爾值,值爲 true 則指示反射的對象在使用時應該取消 Java 語言訪問檢查,從而提升了性能。值爲 false 則指示反射的對象應該實施 Java 語言訪問檢查。
      } catch (Exception e) {
        // Ignored. This is only a final precaution, nothing we can do.
        //忽略。 這只是最後的預防措施,咱們作不了什麼
      }
    }
    if (field.isAccessible()) {當字段修飾符爲private時,咱們須要加上,不然會拋出異常
      if (!setMethods.containsKey(field.getName())) {//當setMethods集合不包含同名屬性時,將其記錄到setMethods集合和setTypes集合
        // 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();//該字段的修飾符
        if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) {//過濾掉final和static修飾的字段
          addSetField(field);//填充setMethods集合和setTypes集合,與上述addGetMethod相似
        }
      }
      if (!getMethods.containsKey(field.getName())) {//當getMethods集合不包含同名屬性時,將其記錄到getMethods集合和getTypes集合
        addGetField(field);//填充getMethods集合和getTypes集合,與上述addGetMethod相似
      }
    }
  }
  if (clazz.getSuperclass() != null) {//有父類
    addFields(clazz.getSuperclass());//遞歸調用,處理父類中定義字段
  }
}

Invoker:ide

public interface Invoker {
  Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;//調用獲取指定字段或執行的方法

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

只有三個實現以下:函數

public class GetFieldInvoker implements Invoker {
  private final Field field;

  public GetFieldInvoker(Field field) {
    this.field = field;
  }

  @Override
  public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
    return field.get(target);//方法返回指定對象上由此Field表示的字段的值。若是該對象具備原始類型,則該值將自動包裝在對象中。
  }

  @Override
  public Class<?> getType() {
    return field.getType();
  }
}

SetFieldInvoker與GetFieldInvoker相相似工具

MethodInvoker的invoker調用Method.invoker實現的性能

 

由ReflectorFactory接口實現對Reflector對象建立與緩存

public interface ReflectorFactory {

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

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

  Reflector findForClass(Class<?> type);//建立指定Class對應的Reflector對象
}

只有一個實現上述接口的實現類:DefaultReflectorFactory

public class DefaultReflectorFactory implements ReflectorFactory {
  private boolean classCacheEnabled = true;//是否開啓對Reflector對象的緩存
  private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<Class<?>, Reflector>();//使用ConcurrentMap集合實現對
Reflector對象的緩存

  public DefaultReflectorFactory() {
  }

  @Override
  public boolean isClassCacheEnabled() {
    return classCacheEnabled;
  }

  @Override
  public void setClassCacheEnabled(boolean classCacheEnabled) {
    this.classCacheEnabled = classCacheEnabled;
  }

  @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);//建立Reflector對象
        reflectorMap.put(type, cached);//放入ConcurrentMap中緩存
      }
      return cached;
    } else {
      return new Reflector(type);//沒開啓緩存則直接建立新對象返回
    }
  }

}
相關文章
相關標籤/搜索