Mybatis源码学习第四课---基础支持层反射模块分析

本文详细介绍了Mybatis的反射模块,包括Reflector、ReflectorFactory、Invoker、TypeParameterResolver等核心组件,它们如何简化反射操作并提高性能。文章通过JavaBean规范引入,详细阐述了各个组件的职责,如Reflector用于存储类的元信息,减少反射开销,MetaObject负责解析属性表达式并提供便捷的字段访问。此外,还提及了ObjectFactory在对象创建中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

   MyBatis 在进行参数处理、结果映射时等操作时,会涉及大量的反射操作。为了简化这些反射相关操作,MyBatisorg.apache.ibatis.reflection 包下提供了专门的反射模块,对反射操作做了近一步封装,提供了更为简洁的 API

一、JavaBean规范

JavaBean 具有如下特征:

  1. 所有的属性都是私有的(通过 getter 和 setter 访问)
  2. 拥有公有的无参构造函数
  3. 提供 setter/getter
  4. 实现 Serializable 接口

二、Reflector 和 ReflectorFactory

   2.1 Reflector 

         出于性能方面的考虑,Mybatis 不是等到使用的时候去解析 XML/反射类,而是为每一个类提供了反射器类 Reflector ,该类中存储了反射需要使用的类的元信息

        MyBatis 提供 Reflector 类来缓存类的字段名和 getter/setter 方法的元信息,使得反射时有更好的性能。使用方式是将原始类对象传入其构造方法,生成 Reflector 对象。

     Reflector 是 MyBatis 中反射模块的基础,每个 Reflector 对象都对应一个类,在 Reflector 中 缓存了反射操作需要使用的类的元信息。 Reflector 中各个字段的含义如下:

  private final Class<?> type;//对于class的类型
  //可读属性的名称集合,存在get方法即可读
  private final String[] readablePropertyNames;
  //可写属性的名称集合,存在set方法即可写
  private final String[] writablePropertyNames;
  //记录了属性相应的 setter 方法, key 是属性名称, value 是 Invoker 对象,它是对 setter 方法对应
  private final Map<String, Invoker> setMethods = new HashMap<>();
  //属性相应的 getter 方法集合, key 是属性名称, value 也是 Invoker 对象
  private final Map<String, Invoker> getMethods = new HashMap<>();
  //记录了属性相应的 setter 方法的参数值类型, key 是属性名称, value 是 setter 方法的参数类型
  private final Map<String, Class<?>> setTypes = new HashMap<>();
  //记录 了属性相应的 getter 方法的返回位类型, key 是属性名称, value 是 getter 方法的返回位类型
  private final Map<String, Class<?>> getTypes = new HashMap<>();
  //默认构造方法
  private Constructor<?> defaultConstructor;
  //记录所有属性的名称集合
  private Map<String, String> caseInsensitivePropertyMap = new HashMap<>();

在 Reflector 的构造方法中会解析指定的 Class 对象,并填充上述集合,具体实现如下:

 public Reflector(Class<?> clazz) {
    type = clazz;//初始化type对象
    //查找 clazz 的默认构造方法(元参构造方法),具体实现是通过反射遥历所有构造方法,代码并不复杂
    addDefaultConstructor(clazz);
    //处理clazz中的get方法信息,填充getMethods、getTypes
    addGetMethods(clazz);
    //处理clazz中的set方法信息,填充setMethods、setTypes
    addSetMethods(clazz);
    //处理没有get、set方法的属性
    addFields(clazz);
    //根据get、set方法初始化可读属性集合和可写属性集合
    readablePropertyNames = getMethods.keySet().toArray(new String[0]);
    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 对应着一个 Class 对象
记录了默认构造函数
其余的是属性及其 setter/gettter 相关

对于一个属性(只有有 setter/getter 才能被称之为属性)
(1)如果是可读的(有 getter 方法),则 Reflector 会将其及其方法处理后放入对应的可读相关的集合中;
(2)如果是可写的(有 setter 方法),则 Reflector 会将其及其方法处理后放入对应的可写相关的集合中;
(3)最后使用 Map<String, String> caseInsensitivePropertyMap 记录所有的属性。
 

    addGetMethods 和 addSetMethods 分别获取类的所有方法,从符合 getter/setter 规范的方法中解析出字段名,并记录方法的参数类型、返回值类型等信息:

  private void addGetMethods(Class<?> clazz) {
    //字段名-get方法
    Map<String, List<Method>> conflictingGetters = new HashMap<>();
    //获取类的所有方法,及其实现接口的方法,并根据方法签名去重
    Method[] methods = getClassMethods(clazz);
    //取get 方法 条件是入参为空,且已get开头
    Arrays.stream(methods).filter(m -> m.getParameterTypes().length == 0 && PropertyNamer.isGetter(m.getName()))
      .forEach(m -> addMethodConflict(conflictingGetters, PropertyNamer.methodToProperty(m.getName()), m));
    resolveGetterConflicts(conflictingGetters);
  }

  public static boolean isGetter(String name) {
    return (name.startsWith("get") && name.length() > 3) || (name.startsWith("is") && name.length() > 2);
  }
 private void addSetMethods(Class<?> clazz) {
    Map<String, List<Method>> conflictingSetters = new HashMap<>();
    Method[] methods = getClassMethods(clazz);
    Arrays.stream(methods).filter(m -> m.getParameterTypes().length == 1 && PropertyNamer.isSetter(m.getName()))
      .forEach(m -> addMethodConflict(conflictingSetters, PropertyNamer.methodToProperty(m.getName()), m));
    resolveSetterConflicts(conflictingSetters);
  }

     对 getter/setter 方法进行去重是通过类似 java.lang.String#getSignature:java.lang.reflect.Method 的方法签名来实现的,如果子类在实现过程中,参数、返回值使用了不同的类型(使用原类型的子类),则会导致方法签名不一致,同一字段就会对应不同的 getter/setter 方法,因此需要进行去重

  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;
        }
        // 字段对应了多个get方法
        Class<?> winnerType = winner.getReturnType();
        Class<?> candidateType = candidate.getReturnType();
        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.");
          } else if (candidate.getName().startsWith("is")) {
            // 返回值为boolean的get方法可能有多个,如getIsSave和isSave,优先取is开头的
            winner = candidate;
          }
        } else if (candidateType.isAssignableFrom(winnerType)) {
          // OK getter type is descendant
          // 可能会出现接口中的方法返回值是List,子类实现方法返回值是ArrayList,使用子类返回值方法
        } 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.");
        }
      }
      // 记录字段名对应的get方法对象和返回值类型
      addGetMethod(propName, winner);
    }
  }

    去重的方式是使用更规范的方法以及使用子类的方法。在确认字段名对应的唯一 getter/setter 方法后,记录方法名对应的方法、参数、返回值等信息。MethodInvoker 可用于调用 Method 类的 invoke 方法来执行 getter/setter 方法(addSetMethods 记录映射关系的方式与 addGetMethods 大致相同)。

private void addGetMethod(String name, Method method) {
  // 过滤$开头、serialVersionUID的get方法和getClass()方法
  if (isValidPropertyName(name)) {
    // 字段名-对应get方法的MethodInvoker对象
    getMethods.put(name, new MethodInvoker(method));
    Type returnType = TypeParameterResolver.resolveReturnType(method, type);
    // 字段名-运行时方法的真正返回类型
    getTypes.put(name, typeToClass(returnType));
  }
}

接下来会执行 addFields 方法,此方法针对没有 getter/setter 方法的字段,通过包装为 SetFieldInvoker 在需要时通过 Field 对象的反射来设置和读取字段值。

private void addFields(Class<?> 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();
      if (!(Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers))) {
        // 非final的static变量,没有set方法,可以通过File对象做赋值操作
        addSetField(field);
      }
    }
    if (!getMethods.containsKey(field.getName())) {
      addGetField(field);
    }
  }
  if (clazz.getSuperclass() != null) {
    // 递归查找父类
    addFields(clazz.getSuperclass());
  }
}

2.2 Invoker

   Invoker 接口用于抽象设置和读取字段值的操作。对于有 getter/setter 方法的字段,通过 MethodInvoker 反射执行;对应其它字段,通过 GetFieldInvokerSetFieldInvoker 操作 Field 对象的 getter/setter 方法反射执行。

public interface Invoker {
  /**
   * 通过反射设置或读取字段值
   *
   * @param target
   * @param args
   * @return
   * @throws IllegalAccessException
   * @throws InvocationTargetException
   */
  Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;

  /**
   * 字段类型
   *
   * @return
   */
  Class<?> getType();
}

                               å¨è¿éæå¥å¾çæè¿°

  • MethodInvoker:有 getter/setter 方法的字段,方法的 Invoker
  • GetFieldInvoker:如果没有 getter,则使用该方法,通过 Filed 类直接读取成员变量的值
  • SetFieldInvoker:如果没有 setter,则使用该方法,通过 Filed 类直接设置成员变量的值

2.3 TypeParameterResolver

  在开始介绍 TypeParameterResolver 之前, 先简单介绍一下 Type 接口的基础知识。 Type 是所有类型的父接口,它有四个子接口和一个实现类。

  • Class:原始类型,Class 类的对象表示 JVM 中的一个类或接口, 每个 Java 类在 JVM 里都表现为一个 Class 对象。
  • ParameterizedType:泛型类型,如:List<String>
  • TypeVariable:泛型类型变量,如: List<T> 中的 T
  • GenericArrayType:组成元素是 ParameterizedTypeTypeVariable 的数组类型,如:List<String>[]T[]
  • WildcardType:通配符泛型类型变量,如:List<?> 中的

     在对 Reflector 的 分析过程中,我们看到了 TypeParameterResolver 的身影,它是一个工具类,提供了一系列静态 方法来解析指定类中的宇段、方法返回值或方法参数的类型。 TypeParameterResolver 中各个静 态方法之间的调用关系大致如图  所示,为保持清晰,其中递归调用没有表现出来,在后面 的代码分析过程中会进行强调,

   TypeParameterResolver 分别提供 resolveFieldTyperesolveReturnTyperesolveParamTypes 方法用于解析字段类型、方法返回值类型和方法入参类型,这些方法均调用 resolveType 来获取类型信息:

 

/**
 * 获取类型信息
 *
 * @param type 根据是否有泛型信息签名选择传入泛型类型或简单类型
 * @param srcType 引用字段/方法的类(可能是子类,字段和方法在父类声明)
 * @param declaringClass 字段/方法声明的类
 * @return
 */
private static Type resolveType(Type type, Type srcType, Class<?> declaringClass) {
  if (type instanceof TypeVariable) {
    // 泛型类型变量,如:List<T> 中的 T
    return resolveTypeVar((TypeVariable<?>) type, srcType, declaringClass);
  } else if (type instanceof ParameterizedType) {
    // 泛型类型,如:List<String>
    return resolveParameterizedType((ParameterizedType) type, srcType, declaringClass);
  } else if (type instanceof GenericArrayType) {
    // TypeVariable/ParameterizedType 数组类型
    return resolveGenericArrayType((GenericArrayType) type, srcType, declaringClass);
  } else {
    // 原始类型,直接返回
    return type;
  }
}

 

   resolveTypeVar 用于解析泛型类型变量参数类型,如果字段或方法在当前类中声明,则返回泛型类型的上界或 Object 类型;如   果在父类中声明,则递归解析父类;父类也无法解析,则递归解析实现的接口

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) {
    // 泛型类型,如 TestObj<String>
    ParameterizedType parameterizedType = (ParameterizedType) srcType;
    // 取原始类型TestObj
    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) {
      // 返回泛型类型变量上界,如:T extends String,则返回String
      return bounds[0];
    }
    // 没有上界返回Object
    return Object.class;
  }

  // 字段/方法在父类中声明,递归查找父类泛型
  Type superclass = clazz.getGenericSuperclass();
  result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superclass);
  if (result != null) {
    return result;
  }

  // 递归泛型接口
  Type[] superInterfaces = clazz.getGenericInterfaces();
  for (Type superInterface : superInterfaces) {
    result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superInterface);
    if (result != null) {
      return result;
    }
  }
  return Object.class;
}

通过调用 scanSuperTypes 实现递归解析:

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) {
      // 子类可能对父类泛型变量做过替换,使用替换后的类型
      parentAsType = translateParentTypeVars((ParameterizedType) srcType, clazz, parentAsType);
    }
    if (declaringClass == parentAsClass) {
      // 字段/方法在当前父类中声明
      for (int i = 0; i < parentTypeVars.length; i++) {
        if (typeVar == parentTypeVars[i]) {
          // 使用变量对应位置的真正类型(可能已经被替换),如父类 A<T>,子类 B extends A<String>,则返回String
          return parentAsType.getActualTypeArguments()[i];
        }
      }
    }
    // 字段/方法声明的类是当前父类的父类,继续递归
    if (declaringClass.isAssignableFrom(parentAsClass)) {
      return resolveTypeVar(typeVar, parentAsType, declaringClass);
    }
  } else if (superclass instanceof Class && declaringClass.isAssignableFrom((Class<?>) superclass)) {
    // 父类是原始类型,继续递归父类
    return resolveTypeVar(typeVar, superclass, declaringClass);
  }
  return null;
}

    解析方法返回值和方法参数的逻辑大致与解析字段类型相同,MyBatis 源码的TypeParameterResolverTest 类提供了相关的测试用例。

2.4 ReflectorFactory

    看名称,工厂方法,是为了创建个缓存 Reflector。MyBatis 还提供 ReflectorFactory 接口用于实现 Reflector 容器,其默认实现为 DefaultReflectorFactory,其中可以使用 classCacheEnabled 属性来配置是否使用缓存。        

/**
 * 创建Reflector的工厂接口
 */
public interface ReflectorFactory {

  /**
   * 检测 ReflectorFactory 对象是否会缓存 Reflector 对象
   */
  boolean isClassCacheEnabled();
  /**
   * 设置是否缓存
   */
  void setClassCacheEnabled(boolean classCacheEnabled);
  /**
   * 缓存中查找 Class 对应的 Reflector 对象,找不到则创建
   */
  Reflector findForClass(Class<?> type);
}

                                   å¨è¿éæå¥å¾çæè¿°

mybatis 为我们提供了该方法的默认实现 DefaultReflectorFactory 。该类的实现很简单,就是通过 ConcurrentMap<Class<?>, Reflector> 对 Reflector 进行缓存。

2.5 ObjectFactory

ObjectFactory 接口是 MyBatis 对象创建工厂,其默认实现 DefaultObjectFactory 通过构造器反射创建对象,支持使用无参构造器和有参构造器。

       MyBatis 中有很多模块会使用到 ObjectFactory 接口,该接口提供了多个 create()方法的重载, 通过这些 create()方法可以创建指定类型的对象。 ObjectFactory 接口的定义如下:

public interface ObjectFactory {

  /**
   * 设置配置信息
   * @param properties
   */
  default void setProperties(Properties properties) {
    // NOP
  }

  //通过无参构造器创建对象
  <T> T create(Class<T> type);

  //根据参数列表,从指定类型中选择合适的构造器创建对象
  <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);

  ///检测指定类型是否为集合类型,主妥处理 java.util.Collection 及其子类
  <T> boolean isCollection(Class<T> type);

}

       DefaultObjectFactory是MyBatis提供的 ObjectFactory接口的唯一实现,它是一个反射工厂, 其 create()方法通过调用 instantiateClass()方法实现。 DefaultObjectFactory.instantiateClass()方法会 根据传入的参数列表选择合适的构造函数实例化对象,具体实现如下:

public class DefaultObjectFactory implements ObjectFactory, Serializable {

  private static final long serialVersionUID = -8855120656740914948L;

  //通过无参构造器创建对象
  @Override
  public <T> T create(Class<T> type) {
    return create(type, null, null);
  }

  @SuppressWarnings("unchecked")
  @Override
  public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    //对象类型
    Class<?> classToCreate = resolveInterface(type);
    // we know types are assignable
    return (T) instantiateClass(classToCreate, constructorArgTypes, constructorArgs);
  }

  //最终创建对象的方法
  private  <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    try {
      Constructor<T> constructor;
      //通过无参数构造器创建对象
      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;
          }
        }
      }
      //根据指定的参数列表查找构造函数,并实例化对象
      constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
      try {
        return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
      } catch (IllegalAccessException e) {
        if (Reflector.canControlMemberAccessible()) {
          constructor.setAccessible(true);
          return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
        } 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);
    }
  }

  protected Class<?> resolveInterface(Class<?> type) {
    Class<?> classToCreate;
    if (type == List.class || type == Collection.class || type == Iterable.class) {
      classToCreate = ArrayList.class;
    } else if (type == Map.class) {
      classToCreate = HashMap.class;
    } else if (type == SortedSet.class) { // issue #510 Collections Support
      classToCreate = TreeSet.class;
    } else if (type == Set.class) {
      classToCreate = HashSet.class;
    } else {
      classToCreate = type;
    }
    return classToCreate;
  }

  @Override
  public <T> boolean isCollection(Class<T> type) {
    return Collection.class.isAssignableFrom(type);
  }

}

2.6 Property 工具集

     反射模块中使用到的三个属性工具类,分别是 PropertyTokenizer 、 PropertyNamer 、PropertyCopier。

  MyBatis 在映射文件定义 resultMap 支持如下形式:

<resultMap id="map" type="Order">
    <result property="orders[0].items[0].name" column="col1"/>
    <result property="orders[0].items[1].name" column="col2"/>
    ...
</resultMap>

rders[0].items[0].name 这样的表达式是由 PropertyTokenizer 解析的,其构造方法能够对表达式进行解析;同时还实现了 Iterator 接口,能够迭代解析表达式。

public PropertyTokenizer(String fullname) {
  // orders[0].items[0].name
  int delim = fullname.indexOf('.');
  if (delim > -1) {
    // name = orders[0]
    name = fullname.substring(0, delim);
    // children = items[0].name
    children = fullname.substring(delim + 1);
  } else {
    name = fullname;
    children = null;
  }
  // orders[0]
  indexedName = name;
  delim = name.indexOf('[');
  if (delim > -1) {
    // 0
    index = name.substring(delim + 1, name.length() - 1);
    // order
    name = name.substring(0, delim);
  }
}

  /**
   * 是否有children表达式继续迭代
   *
   * @return
   */
  @Override
  public boolean hasNext() {
    return children != null;
  }

  /**
   * 分解出的 . 分隔符的 children 表达式可以继续迭代
   * @return
   */
  @Override
  public PropertyTokenizer next() {
    return new PropertyTokenizer(children);
  }

    PropertyNamer 可以根据 getter/setter 规范解析字段名称;PropertyCopier 则支持对有相同父类的对象,通过反射拷贝字段值。

   2.7 MetaClass

    MetaClass 通过 Reflector 和 PropertyTokenizer 组合使用, 实现了对复杂的属性表达式的解 析,并实现了获取指定属性描述信息的功能。 

     Reflector 实现了实体类元信息的封装,但是类中的成员变量是类的情况没有进行处理。

     而 MetaClass 通过 ReflectorFactory 类型的成员变量,实现了实体类中成员变量是类情况的处理,通过与属性工具类的结合,实现了对复杂表达式的解析和实现了获取指定描述信息的功能。
   其成员变量:

public class MetaClass {
  //ReflectorFactory 对象,用于缓存 Reflector 对象
  private ReflectorFactory reflectorFactory;
  //在创建 MetaClass 时会指定一个类,该 Reflector 对象会用于记录该类相关的元信息
  private Reflector reflector;

  MetaClass 的构造函数中会为指定的 Class 创建相应的 Reflector 对象,井用其初始化 MetaClass.reflector 字段

   MetaClass 构造函数是私有的,通过静态方法构建对象

 //私有化构造函数
  private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
    this.reflectorFactory = reflectorFactory;
    //创建reflector对象
    this.reflector = reflectorFactory.findForClass(type);
  }
  //使用静态方法创建 MetaClass 对象 
  public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) {
    return new MetaClass(type, reflectorFactory);
  }

    MetaClass 中比较重要的是 findProperty()方法,它是通过调用 MetaClass. buildProperty()方法 实现的,而 buildProperty()方法会通过 PropertyTokenizer解析复杂的属性表达式,具体实现如下:

public String findProperty(String name) {
    ///委托给 buildProperty()方法实现 
    StringBuilder prop = buildProperty(name, new StringBuilder());
    return prop.length() > 0 ? prop.toString() : null;
  }

/**
   * 解析复杂的属性表达式,例如:<result property="orders[0].items[0].name"column="item1"/> 中 property="orders[0].items[0].name"
   * 案例:
   * @param name tele.name
   * @param builder
   * @return
   */
  private StringBuilder buildProperty(String name, StringBuilder builder) {
    //构造兼解析,name:tele.name
    PropertyTokenizer prop = new PropertyTokenizer(name);//映射文件表达式迭代器
    if (prop.hasNext()) {
      //复杂表达式 //prop.getName():tele propertyName:tele
      String propertyName = reflector.findPropertyName(prop.getName());
      if (propertyName != null) {
        builder.append(propertyName);
        builder.append(".");
        // 加载内嵌字段类型对应的MetaClass
        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;
  }

理解了这个方法(递归,该类中有很多类似的),就可以很好的对这个类进行理解,以查找(richType.richProperty)为例:

  1. 通过 PropertyTokenizer 对表达式进行解析, 得到当前的 name=richType, children=richProperty
  2. 从 reflector 中查找该 richType 属性
  3. 将 richType 添加到 builder 中
  4. 使用 metaClassForProperty 创建 richType 的 MetaClass
  5. 递归调用自身来处理子表达式
  6. 退出的条件就是没有子表达式。这个是为了,我们类中有成员变量是类,我们可以通过其找到他们的所有类及其属性。

注意,在此过程中,ReflectorFactory 一直是同一个,而其内部缓存了多个 Reflector 对象

2.8 ObjectWrapper


    MetaClass 是 MyBatis 对类级别的元信息的封装和处理,下面来看 MyBatis 对对象级别的元 信息的处理。 ObjectWrapper 接口是对对象的包装,抽象了对象的属性信息,它定义了一系列查 询对象属性信息的方法,以及更新属性的方法。 

     相对于 MetaClass 关注类信息,MetalObject 关注的是对象的信息,除了保存传入的对象本身,还会为对象指定一个 ObjectWrapper 将对象包装起来。ObejctWrapper 体系如下:

              

     ObjectWrapper默认实现包括了对 MapCollection 和普通 JavaBean 的包装MyBatis 还支持通过 ObjectWrapperFactory 接口对 ObejctWrapper 进行扩展,生成自定义的包装类。MetaObject 对对象的具体操作,就委托给真正的 ObjectWrapper 处理。

public interface ObjectWrapper {

  //如果ObjectWrapper 中封装的是普通的 Bean 对象,则调用相应属性的相应 getter 方法,
  //如采封装的是集合类,则获取指定 key 或下标对应的 value 位
  Object get(PropertyTokenizer prop);

  //如果 ObjectWrapper 中封装的是普通的 Bean 对象, 则调用相应属性的相应 setter 方法,
   //  如果封装的是集合类,则设置指定 key 或下标对应的 value 值
  void set(PropertyTokenizer prop, Object value);

  //查找属性表达式指定的属性,第二个参数表示是否忽略属性表达式中的下画线
  String findProperty(String name, boolean useCamelCaseMapping);

  String[] getGetterNames();//查找可写属性的名称集合

  String[] getSetterNames();//查找可读属性的名称集合
  //解析属性表达式指定属性的 setter 方法的参数类型
  Class<?> getSetterType(String name);//

  //解析属性表达式指定属性的 getter 方法的返回值类型
  Class<?> getGetterType(String name);

  //判断属性表达式指定属性是否有 getter/setter 方法
  boolean hasSetter(String name);

  boolean hasGetter(String name);

  //为属性表达式指定的属性创建相应的 MetaObject 对象 
  MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory);

  boolean isCollection();

  void add(Object element);

  <E> void addAll(List<E> element);

}

    BaseWrapper 是一个实现了 ObjectWrapper 接口的抽象类, 其中封装了 MetaObject 对象,并 提供了三个常用的方法供其子类使用,

       

    BaseWrapper. resolveCollection()方法会调用 MetaObject. getValue()方法法,它会解析属性表达 式井获取指定的属性, MetaObject.getValue()方法的实现在后面详细介绍。 

    BaseWrapper.getCollectionValue()方法和 setCollectionValue()方法会解析属性表达式的索引 信息,然后获取/设置对应项。这两个方法的实现类似,这里只分析getCollectionValue ()方法


  protected Object getCollectionValue(PropertyTokenizer prop, Object collection) {
    if (collection instanceof Map) {//如果是 Map 类型,如l index 为 key 
      return ((Map) collection).get(prop.getIndex());
    } else {
      int i = Integer.parseInt(prop.getIndex());//如果是其他集合类型,则 index 为下标 
      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[]) {
       ..........................
      } else {
        throw new ReflectionException("The '" + prop.getName() + "' property of " + collection + " is not a List or Array.");
      }
    }
  }

    BeanWrapper 继承了 BaseWrapper 抽象类,其中封装了一个 JavaBean对象以及该 JavaBean 类相应的 MetaClass 对象,当然,还有从 BaseWrapper 继承下来的、该 JavaBean 对象相应的 MetaObject 对象。

    例如赋值操作

  @Override
  public void set(PropertyTokenizer prop, Object value) {
    if (prop.getIndex() != null) {
      // 当前表达式是集合,如:items[0],就需要获取items集合对象
      Object collection = resolveCollection(prop, object);
      // 在集合的指定索引上赋值
      setCollectionValue(prop, collection, value);
    } else {
      // 解析完成,通过Invoker接口做赋值操作
      setBeanProperty(prop, object, value);
    }
  }

  protected Object resolveCollection(PropertyTokenizer prop, Object object) {
    if ("".equals(prop.getName())) {
      return object;
    } else {
      // 在对象信息中查到此字段对应的集合对象
      return metaObject.getValue(prop.getName());
    }
  }

根据 PropertyTokenizer 对象解析出的当前字段是否存在 index 索引来判断字段是否为集合。如果当前字段对应集合,则需要在对象信息中查到此字段对应的集合对象:

public Object getValue(String name) {
  PropertyTokenizer prop = new PropertyTokenizer(name);
  if (prop.hasNext()) {
    // 如果表达式仍可迭代,递归寻找字段对应的对象
    MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
    if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
      return null;
    } else {
      return metaValue.getValue(prop.getChildren());
    }
  } else {
      // 字段解析完成
    return objectWrapper.get(prop);
  }
}

如果字段是简单类型,BeanWrapper 获取字段对应的对象逻辑如下:

@Override
public Object get(PropertyTokenizer prop) {
  if (prop.getIndex() != null) {
    // 集合类型,递归获取
    Object collection = resolveCollection(prop, object);
    return getCollectionValue(prop, collection);
  } else {
    // 解析完成,反射读取
    return getBeanProperty(prop, object);
  }
}

可以看到,仍然是会判断表达式是否迭代完成,如果未解析完字段会不断递归,直至找到对应的类型。前面说到 Reflector 创建过程中将对字段的读取和赋值操作通过 Invoke 接口抽象出来,针对最终获取的字段,此时就会调用 Invoke 接口对字段反射读取对象值:

/**
 * 通过Invoker接口反射执行读取操作
 *
 * @param prop
 * @param object
 */
private Object getBeanProperty(PropertyTokenizer prop, Object object) {
  try {
    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);
  }
}

   对象读取完毕再通过 setCollectionValue 方法对集合指定索引进行赋值或通过 setBeanProperty 方法对简单类型反射赋值。MapWrapper 的操作与 BeanWrapper 大致相同,CollectionWrapper 相对更会简单,只支持对原始集合对象进行添加操作。

   2.9 MetaObject

     ObjectWrapper 提供了获取/设置对象中指 定的属性值、检测 ge出r/setter 等常用功能,但是 ObjectWrapper 只是这些功能的最后一站,我 们省略了对属性表达式解析过程的介绍,而该解析过程是在 MetaObject 中实现的。 

MetaObject中的属性如下:

  //原始 JavaBean 对象
  private final Object originalObject;
  //ObjectWrapper 对象,其中封装了originalObject对象
  private final ObjectWrapper objectWrapper;
  //负责实例化 originalObject 的工厂对象,
  private final ObjectFactory objectFactory;
  //负责创建 ObjectWrapper 的工厂对象
  private final ObjectWrapperFactory objectWrapperFactory;
  //用于创建并缓存 Reflector 对象的工厂对象,
  private final ReflectorFactory reflectorFactory;

MetaObject的构造方法会根据传入的原始对象的类型以及 ObjectFactory 工厂的实现,创建 相应的 ObjectWrapper 对象,代码如下:

private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
  this.originalObject = object;
  this.objectFactory = objectFactory;
  this.objectWrapperFactory = objectWrapperFactory;
  this.reflectorFactory = reflectorFactory;

  // 根据传入object类型不同,指定不同的wrapper
  if (object instanceof ObjectWrapper) {
    this.objectWrapper = (ObjectWrapper) object;
  } else if (objectWrapperFactory.hasWrapperFor(object)) {
    this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
  } else if (object instanceof Map) {
    this.objectWrapper = new MapWrapper(this, (Map) object);
  } else if (object instanceof Collection) {
    this.objectWrapper = new CollectionWrapper(this, (Collection) object);
  } else {
    this.objectWrapper = new BeanWrapper(this, object);
  }
}
  // MetaObject 的构造方法是 private 修改的,只能通过 forObj ect ()这个静态方法创建 MetaObject 对象 
  public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
    if (object == null) {
      return SystemMetaObject.NULL_META_OBJECT;
    } else {
      return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
    }
  }

三、小结

MyBatis 根据自身需求,对反射 API 做了近一步封装。其目的是简化反射操作,为对象字段的读取和赋值提供更好的性能。

  • org.apache.ibatis.reflection.Reflector:缓存类的字段名和 getter/setter 方法的元信息,使得反射时有更好的性能。
  • org.apache.ibatis.reflection.invoker.Invoker::用于抽象设置和读取字段值的操作。
  • org.apache.ibatis.reflection.TypeParameterResolver:针对 Java-Type 体系的多种实现,解析指定类中的字段、方法返回值或方法参数的类型。
  • org.apache.ibatis.reflection.DefaultReflectorFactory:默认的 Reflector 创建工厂。
  • org.apache.ibatis.reflection.factory.ObjectFactory:MyBatis 对象创建工厂,其默认实现 DefaultObjectFactory 通过构造器反射创建对象。
  • org.apache.ibatis.reflection.property:property 工具包,针对映射文件表达式进行解析和 Java 对象的反射赋值。
  • org.apache.ibatis.reflection.MetaClass:依赖 PropertyTokenizer 和 Reflector 查找表达式是否可以匹配 Java 对象中的字段,以及对应字段是否有 getter/setter 方法。
  • org.apache.ibatis.reflection.MetaObject:对原始对象进行封装,将对象操作委托给 ObjectWrapper 处理。
  • org.apache.ibatis.reflection.wrapper.ObjectWrapper:对象包装类,封装对象的读取和赋值等操作。

四、使用实例

 

ReflectorFactory reflectorFactory = new DefaultReflectorFactory();

		//使用Reflector读取类元信息
		Reflector findForClass = reflectorFactory.findForClass(TUser.class);
		Constructor<?> defaultConstructor = findForClass.getDefaultConstructor();
		String[] getablePropertyNames = findForClass.getGetablePropertyNames();
		String[] setablePropertyNames = findForClass.getSetablePropertyNames();
		System.out.println(defaultConstructor.getName());
		System.out.println(Arrays.toString(getablePropertyNames));
		System.out.println(Arrays.toString(setablePropertyNames));
		//反射工具类初始化
		ObjectFactory objectFactory = new DefaultObjectFactory();
		TUser user = objectFactory.create(TUser.class);
		ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
		MetaObject metaObject = MetaObject.forObject(user, objectFactory, objectWrapperFactory, reflectorFactory);
		ObjectWrapper wrapperForUser = new BeanWrapper(metaObject, user);
		String[] getterNames = wrapperForUser.getGetterNames();
		String[] setterNames = wrapperForUser.getSetterNames();
		System.out.println(Arrays.toString(getterNames));
		System.out.println(Arrays.toString(setterNames));

		PropertyTokenizer prop = new PropertyTokenizer("userName");
		wrapperForUser.set(prop, "lison");
		System.out.println(user);
		
		//模拟数据库行数据转化成对象
		//1.模拟从数据库读取数据
		Map<String, Object> dbResult = new HashMap<>();
		dbResult.put("id", 1);
		dbResult.put("user_name", "lison");
		dbResult.put("real_name", "李晓宇");
		TPosition tp = new TPosition();
		tp.setId(1);
		dbResult.put("position_id", tp);
		//2.模拟映射关系
		Map<String, String> mapper = new HashMap<String, String>();
		mapper.put("id", "id");
		mapper.put("userName", "user_name");
		mapper.put("realName", "real_name");
		mapper.put("position", "position_id");

		//3.使用反射工具类将行数据转换成pojo
		BeanWrapper objectWrapper = (BeanWrapper) metaObject.getObjectWrapper();
		Set<Entry<String, String>> entrySet = mapper.entrySet();
		for (Entry<String, String> colInfo : entrySet) {
			String propName = colInfo.getKey();
			Object propValue = dbResult.get(colInfo.getValue());
			PropertyTokenizer proTokenizer = new PropertyTokenizer(propName);
			objectWrapper.set(proTokenizer, propValue);
		}
		System.out.println(metaObject.getOriginalObject());
		
	}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值