MyBatis反射工具模块之Reflector

文章目录

  • 前言
  • 一、01. MyBatis反射工具模块之Reflector
    • 1. 参数注释说明
    • 2. 主要注释方法说明
    • 3. 主要注释子方法详细说明
      • 3.1 addDefaultConstructor
      • 3.1 addGetMethods, addSetMethods
      • 3.2 addFields
  • 总结


前言

用了两年多的Spring Data JPA, 再来熟读一下mybatis源码


一、01. MyBatis反射工具模块之Reflector

1. 参数注释说明

  // 类型
  private final Class<?> type;
  // getter属性名称集合
  private final String[] readablePropertyNames;
  // setter属性名称集合
  private final String[] writablePropertyNames;
  // setter方法集合,key:属性,value: Invoker
  private final Map<String, Invoker> setMethods = new HashMap<>();
  // getter方法集合,key:属性,value: Invoker
  private final Map<String, Invoker> getMethods = new HashMap<>();
  // setter属性类型集合,key:属性名称,value:参数类型
  private final Map<String, Class<?>> setTypes = new HashMap<>();
  // getter属性类型集合,key:属性名称,value:返回值类型
  private final Map<String, Class<?>> getTypes = new HashMap<>();
  // 无参构造
  private Constructor<?> defaultConstructor;
  // 属性名称集合, key: 大写属性名,value:属性名称
  private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();

2. 主要注释方法说明

Reflector 主要方法就是构造函数 Reflector(Class clazz),下面是该方法的注释说明

  //这个方法主要就是通过映射的方式给参数赋值
  public Reflector(Class<?> clazz) {
    // 类型
    type = clazz;
	// 默认无参构造函数赋值
    addDefaultConstructor(clazz);
    // getMethods,getTypes 赋值, getter方法属性名称以及返回值类型获取保存
    addGetMethods(clazz);
    // setMethods,setTypes 赋值, setter方法属性名称以及请求参数类型获取保存
    addSetMethods(clazz);
    // 该对象无getter,setter方法的属性(addGetMethods, addSetMethods 没扫描出来的属性),通过addFields给补上.例如无get,set方法的属性
    // setMethods,setTypes,getMethods,getTypes 赋值
    addFields(clazz);
    // getter属性名称集合
    readablePropertyNames = getMethods.keySet().toArray(new String[0]);
    // setter属性名称集合
    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);
    }
  }

3. 主要注释子方法详细说明

3.1 addDefaultConstructor

  // 默认无参构造函数赋值
  private void addDefaultConstructor(Class<?> clazz) {
    // 获取该对象所有构造函数
    Constructor<?>[] constructors = clazz.getDeclaredConstructors();
    // 筛选出无参构造函数并且赋值
    Arrays.stream(constructors)
      .filter(constructor -> constructor.getParameterTypes().length == 0)// 筛选出无参构造函数
      .findAny()// 获取无参构造函数
      .ifPresent(constructor -> this.defaultConstructor = constructor);// 给Reflector对象属性defaultConstructor赋值
  }

3.1 addGetMethods, addSetMethods


  // getMethods,getTypes 赋值, getter方法属性名称以及返回值类型获取保存
  private void addGetMethods(Class<?> clazz) {
    // 用来装属性集合
    Map<String, List<Method>> conflictingGetters = new HashMap<>();
    // 获取此类所有的方法
    Method[] methods = getClassMethods(clazz);
    // 从getter方法中获取属性名称,加入conflictingGetters集合
    Arrays.stream(methods)
      .filter(m -> m.getParameterTypes().length == 0 && PropertyNamer.isGetter(m.getName())) // 筛选出符合getter的方法
      .forEach(m -> addMethodConflict(conflictingGetters, PropertyNamer.methodToProperty(m.getName()), m)); // 加入conflictingGetters集合
    //解决getter 方法冲突
    resolveGetterConflicts(conflictingGetters);
  }
  
  // 获取此类所有的方法
  private Method[] getClassMethods(Class<?> clazz) {
    // key: 唯一方法key(返回类型#方法名称:参数列表), value:Method
    Map<String, Method> uniqueMethods = new HashMap<>();
    Class<?> currentClass = clazz;
    while (currentClass != null && currentClass != Object.class) {
      // getDeclaredMethods 获取此类所有方法
      // addUniqueMethods给uniqueMethods赋值
      addUniqueMethods(uniqueMethods, currentClass.getDeclaredMethods());

      // 获取此类所有接口
      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[0]);
  }
  
private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {
    // 处理冲突的核心逻辑其实就是比较 getter 方法的返回值,优先选择返回值为子类的 getter 方法
    for (Entry<String, List<Method>> entry : conflictingGetters.entrySet()) {
      // 属性method
      Method winner = null;
      // 属性名称
      String propName = entry.getKey();
      // 是否冲突
      boolean isAmbiguous = false;
      for (Method candidate : entry.getValue()) {
        if (winner == null) {
          winner = candidate;
          continue;
        }
        // 两个 Method 使用返回类型做比较
        Class<?> winnerType = winner.getReturnType();
        Class<?> candidateType = candidate.getReturnType();
        if (candidateType.equals(winnerType)) { // 返回类型有冲突
          if (!boolean.class.equals(candidateType)) { // 判断返回类型是否是boolean
            // 不是boolean 则判断为冲突
            isAmbiguous = true;
            break;
          } else if (candidate.getName().startsWith("is")) { // 为什么是boolean 就不判断为冲突呢?
            // 是boolean类型
            winner = candidate;
          }
        } else if (candidateType.isAssignableFrom(winnerType)) {// winnerType 是 candidateType 子类 或 winnerType实现了candidateType接口
          // OK getter type is descendant
        } else if (winnerType.isAssignableFrom(candidateType)) {// candidateType 是 winnerType 子类 或 candidateType实现了winnerType接口
          winner = candidate;
        } else {
          isAmbiguous = true;
          break;
        }
      }
      // 将属性名称加入集合
      addGetMethod(propName, winner, isAmbiguous);
    }
  }
  
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);
    getMethods.put(name, invoker);
    Type returnType = TypeParameterResolver.resolveReturnType(method, type);
    getTypes.put(name, typeToClass(returnType));
  }

3.2 addFields

  private void addFields(Class<?> clazz) {
    // 获取该类所有字段(不包括父类字段)
    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
      // 添加 setMethods 集合中不存在的字段
      if (!setMethods.containsKey(field.getName())) {
        // 获取属性修饰符
        int modifiers = field.getModifiers();
        // 判断该属性修饰符是否是 final 或 static
        if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) {
          // 加入setMethods,setTypes集合
          addSetField(field);
        }
      }
      // 添加 getMethods 集合中不存在的字段
      if (!getMethods.containsKey(field.getName())) {
        addGetField(field);
      }
    }
    // 通过递归获取改类以及父类所有属性
    if (clazz.getSuperclass() != null) {
      addFields(clazz.getSuperclass());
    }
  }

欢迎补充~


总结

映射大法好!!!

你可能感兴趣的:(MyBatis,java,反射,mybatis,Reflector)