MyBatis源码剖析

[MyBatis源码分析 - 反射器模块 - 组件一] Refl

2020-10-14  本文已影响0人  小胡_鸭

一、简介

  Reflector是整个反射器模块的基础,每个Reflector对象都对应一个类,在其构造函数中,根据传入的Class对象,调用Java的反射API,获取并缓存反射操作需要用到的这个类的元信息。

二、成员属性

  private Class<?> type;      // 对应的Class类型
  private String[] readablePropertyNames = EMPTY_STRING_ARRAY;  // 可读属性的名称集合,可读属性就是存在相应getter方法的属性,初始值为空数组
  private String[] writeablePropertyNames = EMPTY_STRING_ARRAY; // 可写属性的名称集合,可写属性就是存在相应setter方法的属性,初始值为空数组
  private Map<String, Invoker> setMethods = new HashMap<String, Invoker>();   // 记录了属性相应的setter方法,key是属性名称,value是Invoker对象,其封装了setter方法对应的Method对象
  private Map<String, Invoker> getMethods = new HashMap<String, Invoker>();   // 属性相应的getter方法集合,key是属性名称,value是Invoker对象
  private Map<String, Class<?>> setTypes = new HashMap<String, Class<?>>();    // 记录了属性相应的setter方法的参数值类型,key是属性名称,value是setter方法的参数类型
  private Map<String, Class<?>> getTypes = new HashMap<String, Class<?>>();    // 记录了属性相应的getter方法的返回值类型,key是属性名称,value是getter方法的返回值类型
  private Constructor<?> defaultConstructor;                    // 记录了默认的构造方法

  private Map<String, String> caseInsensitivePropertyMap = new HashMap<String, String>(); // 记录了所有属性名称的集合,key统一记录成大写

三、构造方法

  Reflector的构造方法中,会解析执行的Class对象,并填充上述集合,源码如下:

  public Reflector(Class<?> clazz) {
    type = clazz;                   // 初始化type字段
    addDefaultConstructor(clazz);   // 查找clazz的默认构造方法(无参构造方法),通过反射获取所有构造方法,通过遍历找出参数长度为0的构造方法
    addGetMethods(clazz);           // 获取clazz中的getter方法,并填充getMethods集合和getTypes集合
    addSetMethods(clazz);           // 获取clazz中的setter方法,并填充setMethods集合和setTypes集合
    addFields(clazz);               // 处理没有getter/setter的字段

    // 根据getMethods/setMethods集合,初始化可读/写属性的名称集合
    readablePropertyNames = getMethods.keySet().toArray(new String[getMethods.keySet().size()]);
    writeablePropertyNames = setMethods.keySet().toArray(new String[setMethods.keySet().size()]);

    // 初始化caseInsensitivePropertyMap集合,其中记录了所有大写格式的属性名称
    for (String propName : readablePropertyNames) {
      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
    }
    for (String propName : writeablePropertyNames) {
      caseInsensitivePropertyMap.put(propName.toUpperCase(Locale.ENGLISH), propName);
    }
  }

  首先初始化 type 属性,然后在 addDefaultConstructor() 方法中根据传入的Class对象的默认构造方法初始化 defaultConstructor 属性,接着调用 addGetMethods() 方法填充 getMethodsgetTypes 集合,同理调用 addSetMethods() 方法填充 setMethodssetTypes 集合,调用 addFields() 方法去处理没有getter/setter的其余字段,因为底层本质是通过反射来获取和设置属性值,该方法也会填充上述的四个集合,最后再将收集到的属性名根据允许获取和设置值来填充 readablePropertyNameswriteablePropertyNames 集合,再将这两个集合中的所有属性名的大写作为key来填充 caseInsensitivePropertyMap

四、方法功能

1、addDefaultConstructor(Class<?> clazz)

【功能】获取类的默认构造方法。
【源码与注释】

  private void addDefaultConstructor(Class<?> clazz) {
    // 获取类的所有构造方法
    Constructor<?>[] consts = clazz.getDeclaredConstructors();
    // 遍历所有构造方法
    for (Constructor<?> constructor : consts) {
      // 找到无参构造方法,该方法即为默认构造方法
      if (constructor.getParameterTypes().length == 0) {
        // 构造方法有可能被private修饰,需要设置其可以访问
        if (canAccessPrivateMethods()) {
          try {
            constructor.setAccessible(true);
          } catch (Exception e) {
            // Ignored. This is only a final precaution, nothing we can do.
          }
        }
        // 如果无参构造方法有访问的权限,则赋值给defaultConstructor
        if (constructor.isAccessible()) {
          this.defaultConstructor = constructor;
        }
      }
    }
  }

2、canAccessPrivateMethods()

【功能】判断系统安全管理器是否允许修改类的可访问性。
【源码与注释】

  // 判断是否可以修改可访问性
  private static boolean canAccessPrivateMethods() {
    try {
      // 获取系统安全管理器
      SecurityManager securityManager = System.getSecurityManager();
      // 如果设置了安全管理器,检查是否有通过反射来访问protected、private的成员和方法的权限
      if (null != securityManager) {
        securityManager.checkPermission(new ReflectPermission("suppressAccessChecks"));
      }
    } catch (SecurityException e) {
      // 如果没有权限,则权限检查会抛出异常,返回false表示不允许访问私有方法
      return false;
    }
    // 如果未设置安全管理器,或者有指定权限,则返回true表示允许访问私有方法
    return true;
  }

3、addGetMethods()

【功能】获取类的 getter 方法并填充 getMethodsgetTypes 集合。
【源码与注释】

  private void addGetMethods(Class<?> cls) {
    // (1)定义属性名和对应getter方法的映射
    Map<String, List<Method>> conflictingGetters = new HashMap<String, List<Method>>();
    // (2)获取当前类及其父类中定义的所有方法
    Method[] methods = getClassMethods(cls);
    // (3)遍历所有方法,筛选出 getter 方法并添加到 conflictingGetters 中
    for (Method method : methods) {
      String name = method.getName();
      // 筛选出getter方法: 一般属性名为aaBb对应的getter方法为getAaBb()
      //                  如果属性是布尔值,则对应的getter方法为isAaBb()
      // 如果子类重写覆盖了父类getter方法导致方法签名不一致
      // eg:
      //   父类定义:  List<String> getList()      方法签名为: java.util.List<String>#getList
      //   子类定义: ArrayList<String> getList() 方法签名为: java.util.ArrayList<String>#getList
      // 我们要取的肯定是返回参数类型更加具体的方法,但是方法签名不一致导致冲突,就先将属性名和对应的冲突方法缓存到conflictingGetters
      // 再交给resolveGetterConflicts()方法进一步处理
      // (3.1)以 get 和 is 开头,并且方法名长度分别长于 3 和 2 才表明这是个 getter 方法
      if (name.startsWith("get") && name.length() > 3) {
        // (3.2)只有方法参数个数为0的方法才是 getter 方法
        if (method.getParameterTypes().length == 0) {
          // (3.3)根据方法名获取属性名
          name = PropertyNamer.methodToProperty(name);
          // (3.4)属性名和方法的映射添加到 conflictingGetters 中
          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);
        }
      }
    }
    // (4)解决签名不同但是方法重复的 getter 方法,一般属性的 getter 只需要有一个即可
    resolveGetterConflicts(conflictingGetters);
  }

【解析】
(1)定义属性名和 getter 方法的映射,因为子类可能重写父类方法,比如返回值类型更加具体,所以映射的值是一个列表。
(2)调用 #getClassMethods() 方法来获取类的所有方法,包括实现接口定义的方法、继承自父类的方法,并沿着继承链向上追溯,具体实现可阅读下面关于该方法的详解。
(3)遍历所有方法,筛选出 getter 方法

  private void addMethodConflict(Map<String, List<Method>> conflictingMethods, String name, Method method) {
    // 获取List
    List<Method> list = conflictingMethods.get(name);
    // List为空,说明该属性是第一次,先创建List,再将List添加到conflictingMethods中
    if (list == null) {
      list = new ArrayList<Method>();
      conflictingMethods.put(name, list);
    }
    // 往Method List中添加Method
    list.add(method);
  }

(4)调用 #resolveGetterConflicts(Map<String, List<Method>>) 方法解决签名不同但是方法重复的 getter 方法的问题,一般属性的 getter 只需要有一个即可,详解参见下面对该方法的介绍。

4、getClassMethods(Class<?> cls)

【功能】获取类cls及其超类中声明的方法,及其实现的接口方法,使用本方法而不是更简单的 Class.getMethods() 是因为我们也想获取被声明为 private 的方法。
【源码与注释】

  private Method[] getClassMethods(Class<?> cls) {
    // (1)用于记录指定类中定义的全部方法的唯一签名以及对应的Method对象
    Map<String, Method> uniqueMethods = new HashMap<String, Method>();
    // (2)表示当前在while循环体中被解析声明方法所属的类,将从cls到cls的父类,最终为Object类
    Class<?> currentClass = cls;
    while (currentClass != null) {
      // (3)记录currentClass这个类中定义的全部方法
      // PS.只能获取类内定义的普通方法,对于继承的方法无法通过反射获取
      addUniqueMethods(uniqueMethods, currentClass.getDeclaredMethods());

      // (4)我们也要寻找接口方法,因为类可能是抽象的,可能实现了接口方法,这些方法无法通过上面的反射获取
      // 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());
      }

      // (5)获取父类,继续循环,获取从父类继承的方法
      currentClass = currentClass.getSuperclass();
    }

    // (6)将 uniqueMethods 中的值即方法取出来放 methods 集合中
    Collection<Method> methods = uniqueMethods.values();

    // (7)将 methods 集合转化为 Method 数组返回
    return methods.toArray(new Method[methods.size()]);
  }

【解析】
(1)定义局部变量 uniqueMethods:存储方法签名和方法的映射关系,方法签名可以看成是每个方法的唯一标识,其组成规则可以看下面关于 #addUniqueMethods() 方法的详解。
(2)定义局部变量 currentClass:表示当前被解析方法的类,将一直沿着继承链向上循环,从cls到cls的父类,最终为Object类。
(3)调用 #addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods) 方法记录当前类中定义的所有方法到 uniqueMethods 中,其源码实现如下:

  private void addUniqueMethods(Map<String, Method> uniqueMethods, Method[] methods) {
    for (Method currentMethod : methods) {
      // (3.1)过滤掉桥接方法,桥接方法不是类中定义的方法,而是编译器为了兼容自动生成的方法
      if (!currentMethod.isBridge()) {
        // (3.2)获取方法签名
        // 通过Reflector.getSignature()方法得到的方法签名是: 返回值类型#方法名称:参数类型列表。
        // 例如,Reflector.getSignature(Method)方法的唯一签名是:
        // java.lang.String#getSignature:java.lang.reflect.Method
        // 通过Reflector.getSignature()方法得到的方法签名是全局唯一的,可以作为该方法的唯一标识
        String signature = getSignature(currentMethod);

        // (3.3)检测在子类中是否已经添加过该方法,如果在子类中已经添加过,则表示子类覆盖了该方法,
        // 无须再想uniqueMethods集合中添加该方法了
        // check to see if the method is already known
        // if it is known, then an extended class must have
        // overridden a method
        if (!uniqueMethods.containsKey(signature)) {
          if (canAccessPrivateMethods()) {
            try {
              currentMethod.setAccessible(true);
            } catch (Exception e) {
              // Ignored. This is only a final precaution, nothing we can do.
            }
          }
          // (3.4)记录该签名和方法的对应关系
          uniqueMethods.put(signature, currentMethod);
        }
      }
    }
  }
  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();
  }

其组成规则为:方法返回值类型#方法名:参数1类型,参数2类型,参数3类型,...,参数名n类型
eg:void#addUniqueMethods:Map<String, Method>,Method[]

(4)获取当前类实现的接口,并遍历接口调用 #addUniqueMethods(Map<String, Method>, Method[]) 获得接口中定义的方法。
(5)获取父类,继续循环,获取从父类继承的方法。
(6)循环结束后,将 uniqueMethods 中的值即获取到的类的所有方法放到 methods 集合中。
(7)将 methods 集合转化为 Method 数组返回。

5、resolveGetterConflicts(Map<String, List<Method>> conflictingGetters)

【功能】解决一个属性有多个 getter 方法的问题,并调用 #addGetMethod(String name, Method method) 方法真正填充 getMethodsgetTypes 集合。
【源码与注释】

  private void resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) {
    // (1)对每个属性的方法逐个处理
    for (String propName : conflictingGetters.keySet()) {
      List<Method> getters = conflictingGetters.get(propName);
      Iterator<Method> iterator = getters.iterator();
      Method firstMethod = iterator.next();
      // (2)该字段只有一个getter方法,没有冲突,直接添加到getMethods集合并填充getTypes集合
      if (getters.size() == 1) {
        addGetMethod(propName, firstMethod);
      } else {
        // (3)同一属性名称存在多个getter方法,则需要对比这些getter方法的返回值,选择getter方法
        // 迭代过程中的临时变量,用于记录迭代到目前为止,最适合作为getter方法的Method
        Method getter = firstMethod;
        // (3.1)记录返回值类型
        Class<?> getterType = firstMethod.getReturnType();
        while (iterator.hasNext()) {
          Method method = iterator.next();
          Class<?> methodType = method.getReturnType();
          if (methodType.equals(getterType)) {
            // (3.2)返回值相同,实际上没有冲突,证明方法签名生成那个可能有问题了,抛出异常
            throw new ReflectionException("Illegal overloaded getter method with ambiguous type for property "
                + propName + " in class " + firstMethod.getDeclaringClass()
                + ".  This breaks the JavaBeans " + "specification and can cause unpredicatble results.");
          } else if (methodType.isAssignableFrom(getterType)) {
            // (3.3)假如判断结果为true,表示methodType是getterType的继承父类或实现的接口
            // 当前最合适的方法(getter)的返回值是当前方法(method)返回值的子类,什么都不做,当前最适合的方法依然不变
            // OK getter type is descendant
          } else if (getterType.isAssignableFrom(methodType)) {
            // (3.4)当前方法的返回值是当前最适合的方法的返回值的子类,更新临时变量getter,当前的getter方法成为最适合的getter方法
            getter = method;
            getterType = methodType;
          } else {
            // (3.5)返回值相同,二义性,抛出异常
            throw new ReflectionException("Illegal overloaded getter method with ambiguous type for property "
                + propName + " in class " + firstMethod.getDeclaringClass()
                + ".  This breaks the JavaBeans " + "specification and can cause unpredicatble results.");
          }
        }
        // (4)while循环结束筛选出最合适的方法之后,调用addGetMethod()方法填充getMethods和getTypes集合
        addGetMethod(propName, getter);
      }
    }
  }

【解析】
(1)遍历逐个处理每个属性,因为子类可以覆盖重写父类的方法,所以一个属性可能有多个 getter 方法
(2)如果属性只有一个 getter 方法,没有冲突,则直接调用 #addGetMethod(String name, Method method) 方法填充处理。
(3)同一属性可能有多个 getter 方法,定义局部变量 getter 存储当前最合适的getter

// 父类
public class SupClass {
    private List userList;
    public List getUserList() {
        return userList;
    }
}
// 子类
public class SubClass {
    private List userList;
    public List getUserList() {
        return userList;
    }
}
// 父类
public class SupClass() {
    private List userList;
    // 当前遍历到的method,methodType为List
    public List getUserList() {
        return userList;
    }
}
// 子类
public class SubClass {
    private ArrayList userList;
    // 当前遍历筛选到的最合适的getter,getterType为ArrayList
    public ArrayList getUserList() {
        return userList;
    }
}

6、addGetMethod(String name, Method method)

【功能】筛选合法的属性名,将方法封装成 MethodInvoker 作为 value,属性名作为 key 填充 getMethods 集合;解析方法返回的真正类型(因为有可能带泛型、通配符等)作为 value,属性名作为 key 填充 getTypes 集合。
【源码与注释】

  private void addGetMethod(String name, Method method) {
    // (1)筛选过滤掉非法的属性名
    if (isValidPropertyName(name)) {
      // (2)将属性名以及对应的MethodInvoker对象添加到getMethods集合中,MethodInvoker是对Method对象反射操作的封装
      getMethods.put(name, new MethodInvoker(method));

      // (3)因为方法返回值中可能带有泛型,eg: List<T>
      // 所以通过TypeParameterResolver.resolveReturnType()方法将类型信息解析到Type对象中
      Type returnType = TypeParameterResolver.resolveReturnType(method, type);

      // (4)将属性名称和对应的返回值类型添加到getTypes集合中保存
      getTypes.put(name, typeToClass(returnType));
    }
  }

【解析】
(1)调用 #isValidPropertyName(String) 方法过滤出合理的属性名,合理的标准是:

  private boolean isValidPropertyName(String name) {
    return !(name.startsWith("$") || "serialVersionUID".equals(name) || "class".equals(name));
  }

(2)根据 method 对象封装创建 MethodInvoker 作为 value,属性名为 key 填充 getMethods 集合。
(3)调用 #TypeParameterResolver.resolveReturnType(Method method, Type srcType) 解析返回值的具体类型(关于该工具类的解析过程可参考:[MyBatis源码分析 - 反射器模块 - 组件四] TypeParameterResolver
),并调用 #typeToClass(Type src) 方法将返回类型对应的 Type 对象转化为 Class 对象并填充 getTypes 集合。,其源码如下:

  private Class<?> typeToClass(Type src) {
    Class<?> result = null;
    // 普通类型,直接使用类
    if (src instanceof Class) {
      result = (Class<?>) src;
    // 参数化类型,使用原始类型,如参数化类型List<String>的原始类型是List
    } else if (src instanceof ParameterizedType) {
      result = (Class<?>) ((ParameterizedType) src).getRawType();
    // 泛型数据类型,形如A<T>[]或T[],前者的数组元素类型是ParameterizedType,后者是TypeVariable
    // 当然,经过TypeParameterResolver的处理,里面的泛型已被解析为具体类型,如List<String>[]、String[]
    } else if (src instanceof GenericArrayType) {
      Type componentType = ((GenericArrayType) src).getGenericComponentType();
      // 数组元素已经是一个具体类型,直接返回形如String[]对应的Class对象即可
      if (componentType instanceof Class) {
        result = Array.newInstance((Class<?>) componentType, 0).getClass();
      } else {
        // 数组元素依然不是一个普通类型,如List<String>[],递归调用typetoClass方法处理,如上会返回List
        // 最终返回的result为List[]
        Class<?> componentClass = typeToClass(componentType);
        result = Array.newInstance((Class<?>) componentClass, 0).getClass();
      }
    }
    if (result == null) {
      result = Object.class;
    }
    return result;
  }

7、addSetMethods(Class<?> cls)

【功能】获取类的 setter 方法,并提取属性名,填充 setMethodssetTypes 集合。
【源码与注解】

  private void addSetMethods(Class<?> cls) {
    // 属性名与其 setter 方法的映射
    Map<String, List<Method>> conflictingSetters = new HashMap<String, List<Method>>();
    // 获取类的所有方法
    Method[] methods = getClassMethods(cls);
    // 遍历所有方法
    for (Method method : methods) {
      String name = method.getName();
      // 筛选出符合 setter 方法名规则的方法
      if (name.startsWith("set") && name.length() > 3) {
        // setter 方法的参数个数应该为1
        if (method.getParameterTypes().length == 1) {
          // 根据方法名提取出属性名,eg: getUser() => user
          name = PropertyNamer.methodToProperty(name);
          // 将属性与其 setter 方法的映射添加到conflictingSetters中
          addMethodConflict(conflictingSetters, name, method);
        }
      }
    }
    // 解决同个属性名有多个冲突的 setter 方法的问题
    resolveSetterConflicts(conflictingSetters);
  }

【解析】
  跟 #addGetMethods(Class<?> cls) 方法的处理过程大同小异,setter 方法不管参数类型是否布尔值,方法名都形如 setXxx,并且参数个数必须为1,然后提取属性名,添加到 conflictingSetters 映射中,最后调用 #resolveSetterConflicts(Map<String, List<Method>> conflictingSetters) 方法处理 setter 方法冲突。

8、resolveSetterConflicts(Map<String, List<Method>> conflictingSetters)

【功能】为类的每个属性挑选出最合适的 setter 方法,并调用 #addSetMethod(String name, Method method) 方法处理填充 setMethodssetTypes 集合。
【源码与注解】

  private void resolveSetterConflicts(Map<String, List<Method>> conflictingSetters) {
    // (1)逐个处理每个属性,为其找到最合适的 setter 方法,因为子类可以覆盖父类的方法,所以一个属性可能有多个 setter 方法
    for (String propName : conflictingSetters.keySet()) {
      List<Method> setters = conflictingSetters.get(propName);
      Method firstMethod = setters.get(0);
      // (2)只有一个 setter 方法,直接调用addSetMethod方法填充setMethods和setTypes集合
      if (setters.size() == 1) {
        addSetMethod(propName, firstMethod);
      } else {
        // (3)获取正在筛选 setter 方法的属性的 getter 方法的返回类型,应该跟 setter 的参数类型一致
        Class<?> expectedType = getTypes.get(propName);
        // (3.1)属性有setter却没有getter方法,存在二义性,不符合JavaBeans的规范,直接抛出异常
        if (expectedType == null) {
          throw new ReflectionException("Illegal overloaded setter method with ambiguous type for property "
              + propName + " in class " + firstMethod.getDeclaringClass() + ".  This breaks the JavaBeans " +
              "specification and can cause unpredicatble results.");
        } else {
          Iterator<Method> methods = setters.iterator();
          Method setter = null;
          while (methods.hasNext()) {
            Method method = methods.next();
            // (3.2)setter参数个数应该只有一个并且参数类型跟getter方法的返回值类型相同,不符合则循环
            if (method.getParameterTypes().length == 1
                && expectedType.equals(method.getParameterTypes()[0])) {
              setter = method;
              break;
            }
          }
          // (4)如果循环结束还没找到setter方法,则抛出异常
          if (setter == null) {
            throw new ReflectionException("Illegal overloaded setter method with ambiguous type for property "
                + propName + " in class " + firstMethod.getDeclaringClass() + ".  This breaks the JavaBeans " +
                "specification and can cause unpredicatble results.");
          }
          // (5)while循环结束筛选出最合适的方法之后,调用addSetMethod()方法填充setMethods和setTypes集合
          addSetMethod(propName, setter);
        }
      }
    }
  }

【详解】
(1)(2)步的处理与 #resolveGetterConflicts(Map<String, List<Method>> conflictingGetters) 类似。
(3)一个符合 JavaBean 规范的类应该同时有 getter 和 setter,并且 getter 的返回类型和 setter 的参数类型一致;程序先去处理 getter,所以这里先根据属性名从 getTypes 获取到 getter 的返回类型。

  private void addSetMethod(String name, Method method) {
    // 筛选过滤掉非法的属性名
    if (isValidPropertyName(name)) {
      // 将属性名以及对应的MethodInvoker对象添加到setMethods集合中,MethodInvoker是对Method对象反射操作的封装
      setMethods.put(name, new MethodInvoker(method));

      // 因为方法返回值中可能带有泛型,eg: List<T>
      // 所以通过TypeParameterResolver.resolveReturnType()方法将类型信息解析到Type对象中
      Type[] paramTypes = TypeParameterResolver.resolveParamTypes(method, type);

      // 将属性名称和对应的返回值类型添加到setTypes集合中保存
      setTypes.put(name, typeToClass(paramTypes[0]));
    }
  }

9、addFields(Class<?> clazz)

【功能】对于没有 getter 和 setter 的属性,通过本方法处理,填充到 getMethodsgetTypessetMethodssetTypes集合中,在获取设置这些属性值时,是通过 Field 对象的反射方法 getset实现的,是对 #addSetMethods(...)#addGetMethods(...) 方法的补充。
【源码与注解】

  private void addFields(Class<?> clazz) {
    // (1)获取类中声明的所有field属性,包含了已经解析出来的有 getter&setter 的属性
    Field[] fields = clazz.getDeclaredFields();
    // 遍历field属性
    for (Field field : fields) {
      // 设置私有属性访问权限
      if (canAccessPrivateMethods()) {
        try {
          field.setAccessible(true);
        } catch (Exception e) {
          // Ignored. This is only a final precaution, nothing we can do.
        }
      }
      if (field.isAccessible()) {
        // (2)过滤掉已经有 getter 和 setter 的属性
        if (!setMethods.containsKey(field.getName())) {
          // (2.1)获取类的修饰符,过滤掉被声明为static final的属性,这些属性只能被类加载器设置其初始值
          int modifiers = field.getModifiers();
          if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) {
            // (2.2)
            addSetField(field);
          }
        }
        if (!getMethods.containsKey(field.getName())) {
          // (2.3)
          addGetField(field);
        }
      }
    }
    // (3)获取父类,找出父类中声明的属性
    if (clazz.getSuperclass() != null) {
      addFields(clazz.getSuperclass());
    }
  }

【详解】
(1)获取类中声明的所有field属性,包含了已经解析出来的有 getter&setter 的属性。
(2)过滤掉已经有 getter&setter 的属性。

  private void addSetField(Field field) {
    // 过滤掉非法的属性
    if (isValidPropertyName(field.getName())) {
      // 创建封装了属性对应Field对象的SetFieldInvoker对象,内部利用Field的set方法来反射设置属性值
      setMethods.put(field.getName(), new SetFieldInvoker(field));
      // 解析获取属性值的具体类型(如果带泛型或通配符)
      Type fieldType = TypeParameterResolver.resolveFieldType(field, type);
      // 将属性和属性值类型对应的Class对象映射填充setTypes集合
      setTypes.put(field.getName(), typeToClass(fieldType));
    }
  }
  private void addGetField(Field field) {
    // 过滤掉非法的属性
    if (isValidPropertyName(field.getName())) {
      // 创建封装了属性对应Field对象的GetFieldInvoker对象,内部利用Field的get方法来反射设置属性值
      getMethods.put(field.getName(), new GetFieldInvoker(field));
      // 解析获取属性值的具体类型(如果带泛型或通配符)
      Type fieldType = TypeParameterResolver.resolveFieldType(field, type);
      // 将属性和属性值类型对应的Class对象映射填充setTypes集合
      getTypes.put(field.getName(), typeToClass(fieldType));
    }
  }

(3)获取父类,通过递归调用本方法找出父类中声明的属性。

10、其他方法

【功能】主要是对 Reflector 类中的属性的使用,对外暴露使用的方法。

五、ReflectorFactory

  ReflectorFactory 是一个接口,定义了创建和缓存 Reflector 对象的方法,只有一个实现类 DefaultReflectorFactory,类关系图如下:


  ReflectorFactory 接口定义如下:
public interface ReflectorFactory {
  // 判断和设置是否有缓存Reflector对象
  boolean isClassCacheEnabled();

  void setClassCacheEnabled(boolean classCacheEnabled);

  // 根据传入的Class对象,创建对应的Reflector对象
  Reflector findForClass(Class<?> type);
}

【解析】
  #isClassCacheEnabled()#setClassCacheEnabled() 方法提供了调用代码Reflector工厂对象是否有缓存生成的 Reflector 对象的信息,#findForClass(Class<?> type) 方法则是根据传入的 Class 对象创建 Reflector 对象。

  唯一一个实现类 DefaultReflectorFactory 的源码如下:

public class DefaultReflectorFactory implements ReflectorFactory {
  // 判断是否要缓存Reflector对象的标志位
  private boolean classCacheEnabled = true;
  // Reflector对象缓存
  private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<Class<?>, Reflector>();

  public DefaultReflectorFactory() {
  }

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

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

  @Override
  public Reflector findForClass(Class<?> type) {
    // 如果有缓存,则先尝试从缓存中取,如果缓存中没有则先创建Reflector对象,再放入缓存,最后返回
    if (classCacheEnabled) {
            // synchronized (type) removed see issue #461
      Reflector cached = reflectorMap.get(type);
      if (cached == null) {
        cached = new Reflector(type);
        reflectorMap.put(type, cached);
      }
      return cached;
    } else {
      // 如果没有缓存,直接创建Reflector对象即可
      return new Reflector(type);
    }
  }
}

【解析】
  代码比较简单,通过一个布尔型的标志位 classCacheEnabled 判断是否要对生成的 Reflector 对象进行缓存,前两个接口方法的实现也依赖于这个标志位;定义了一个并发容器 reflectorMap 缓存 Class 对象及 Reflector 对象的映射关系,将并发控制委托给 ConcurrentMap,#findForClass() 方法中,如果有缓存,先从缓存中取,如果不为空直接返回,如果为空则先创建再缓存最后返回,如果没缓存,则每次都直接创建返回。

六、测试案例

  先来个简单的,不带继承关系,不带泛型的JavaBean,如下:

public class ReflectorTest {
    // 简单Java类
    static class SimpleJavaBean {
        private Long id;
        private String username;
        private double money;

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        @Override
        public String toString() {
            return "{ id:" + id + ", username:" + username + ", money:" + money + " }";
        }
    }
}

  测试案例覆盖了 Reflector 对外暴露的所有方法,单元测试代码如下:

    @Test
    public void testSimpleJavaBean() throws InvocationTargetException, IllegalAccessException {
        ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
        Reflector reflector = reflectorFactory.findForClass(SimpleJavaBean.class);
        Assert.assertTrue(reflector.hasDefaultConstructor());

        String[] readablePropertyNames = reflector.getGetablePropertyNames();
        Assert.assertEquals(3, readablePropertyNames.length);
        // 输出 money id username,虽然money没有显式的getter,但是可以通过反射获取,所以也是可读属性
        System.out.println("[readablePropertyNames] ");
        for (String name : readablePropertyNames)
            System.out.print(name + " ");

        System.out.println();
        String[] writeablePropertyNames = reflector.getSetablePropertyNames();
        Assert.assertEquals(3, writeablePropertyNames.length);
        System.out.println("[writeablePropertyNames]");
        for (String name : writeablePropertyNames)
            System.out.print(name + " ");
        System.out.println();

        Assert.assertEquals(Long.class, reflector.getGetterType("id"));
        Assert.assertEquals(String.class, reflector.getSetterType("username"));
        Assert.assertEquals(double.class, reflector.getGetterType("money"));

        Assert.assertTrue(reflector.hasGetter("id"));
        Assert.assertTrue(reflector.hasSetter("money"));

        Assert.assertEquals("id", reflector.findPropertyName("ID"));
        Assert.assertEquals("username", reflector.findPropertyName("Username"));

        SimpleJavaBean bean = new SimpleJavaBean();
        System.out.println("bean(before call Invoker): " + bean);
        Invoker idSetInvoker = reflector.getSetInvoker("id");
        idSetInvoker.invoke(bean, new Object[]{100L});
        Invoker idGetInvoker = reflector.getGetInvoker("id");
        Assert.assertEquals(100L, idGetInvoker.invoke(bean, new Object[] {}));
        Invoker usernameSetInvoker = reflector.getSetInvoker("username");
        usernameSetInvoker.invoke(bean, new Object[]{"zhangsan"});
        Invoker moneySetInvoker = reflector.getSetInvoker("money");
        moneySetInvoker.invoke(bean, new Object[]{2.33});
        System.out.println("bean(after call Invoker): " + bean);
    }

  执行结果如下:



  复杂一点,经过上面的源码分析可知,解析类属性时不仅会解析类中定义的,还会通过解析接口和父类获取 getter/setter 方法,最后解析出属性名和属性类型,所以定义一个测试接口和实现了接口的抽象父类,最后被测试的类继承了抽象父类,代码如下:

    // 接口定义
    static interface Entity<T> {
        T getId();
        void setId(T id);
    }

    // 抽象父类实现了接口
    static abstract class AbstractEntity implements Entity<Long> {
        private Long id;

        @Override
        public Long getId() {
            return id;
        }

        @Override
        public void setId(Long id) {
            this.id = id;
        }
    }

    // 类继承了父类,间接实现了接口
    static class Section extends AbstractEntity {
    }

  测试代码聚焦是否能获取到继承的属性和正确解析类型,如下:

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

    @Test
    public void testGetGetterType() throws Exception {
        ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
        Reflector reflector = reflectorFactory.findForClass(Section.class);
        Assert.assertEquals(Long.class, reflector.getGetterType("id"));
    }

    @Test
    public void shouldNotGetClass() throws Exception {
        ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
        Reflector reflector = reflectorFactory.findForClass(Section.class);
        Assert.assertFalse(reflector.hasGetter("class"));
    }

  执行结果:



  更复杂一些,属性的类型可能是比较复杂的类型,比如链表List、数组,属性可能是私有的,一般带泛型的类是设计用来复用的,其中子类继承带泛型的父类并且指定类型是一种常用的形式,所以类定义如下:

  static abstract class Parent<T extends Serializable> {
    protected T id;
    protected List<T> list;
    protected T[] array;
    private T fld;
    public T pubFld;
    public T getId() {
      return id;
    }
    public void setId(T id) {
      this.id = id;
    }
    public List<T> getList() {
      return list;
    }
    public void setList(List<T> list) {
      this.list = list;
    }
    public T[] getArray() {
      return array;
    }
    public void setArray(T[] array) {
      this.array = array;
    }
    public T getFld() {
      return fld;
    }
  }

  static class Child extends Parent<String> {
  }

  测试代码如下:

    // 测试是否能解析出泛型
    @Test
    public void shouldResolveSetterParam() throws Exception {
        ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
        Reflector reflector = reflectorFactory.findForClass(Child.class);
        assertEquals(String.class, reflector.getSetterType("id"));
    }

    // 测试解析复杂的类型链表
    @Test
    public void shouldResolveParameterizedSetterParam() throws Exception {
        ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
        Reflector reflector = reflectorFactory.findForClass(Child.class);
        assertEquals(List.class, reflector.getSetterType("list"));
    }

    // 测试解析复杂的类型数组
    @Test
    public void shouldResolveArraySetterParam() throws Exception {
        ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
        Reflector reflector = reflectorFactory.findForClass(Child.class);
        Class<?> clazz = reflector.getSetterType("array");
        assertTrue(clazz.isArray());
        assertEquals(String.class, clazz.getComponentType());
    }

    @Test
    public void shouldResolveGetterType() throws Exception {
        ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
        Reflector reflector = reflectorFactory.findForClass(Child.class);
        assertEquals(String.class, reflector.getGetterType("id"));
    }

    @Test
    public void shouldResolveSetterTypeFromPrivateField() throws Exception {
        ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
        Reflector reflector = reflectorFactory.findForClass(Child.class);
        assertEquals(String.class, reflector.getSetterType("fld"));
    }

    @Test
    public void shouldResolveGetterTypeFromPublicField() throws Exception {
        ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
        Reflector reflector = reflectorFactory.findForClass(Child.class);
        assertEquals(String.class, reflector.getGetterType("pubFld"));
    }

    @Test
    public void shouldResolveParameterizedGetterType() throws Exception {
        ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
        Reflector reflector = reflectorFactory.findForClass(Child.class);
        assertEquals(List.class, reflector.getGetterType("list"));
    }

    @Test
    public void shouldResolveArrayGetterType() throws Exception {
        ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
        Reflector reflector = reflectorFactory.findForClass(Child.class);
        Class<?> clazz = reflector.getGetterType("array");
        assertTrue(clazz.isArray());
        assertEquals(String.class, clazz.getComponentType());
    }

  执行结果:


  通过上面几个测试案例,可以比较好地学习掌握 Reflector 的用法。
上一篇下一篇

猜你喜欢

热点阅读