MyBatis源码分析之基础支持层反射

(/≧▽≦)/~┴┴ 嗨~我叫小奥 ✨✨✨
👀👀👀 个人博客:小奥的博客
👍👍👍:个人CSDN
⭐️⭐️⭐️:传送门
🍹 本人24应届生一枚,技术和水平有限,如果文章中有不正确的内容,欢迎多多指正!
📜 欢迎点赞收藏关注哟! ❤️

2.2 反射模块

MyBatis在进行参数处理、结果集映射等操作时会使用到大量的反射操作,Java中的反射功能虽然强大,但是编码比较复杂且容易出错,为了简化反射相关的代码,MyBatis提供了专门的反射模块,对Java原生反射进行了封装,提供更加简单易用的api。

反射模块目录如下:

在这里插入图片描述

包路径:org.apache.ibatis.reflection

主要分析一下几个包中的类:

  • 对象工厂包。reflection包下的factory子包时一个对象工厂子包。该包中的类用来基于反射生产出各种对象。
  • 执行器包
  • 属性子包
  • 对象包装器包反射核心类
  • 反射包装类
  • 异常拆包工具
  • 参数名解析器
  • 泛型解析器

① 对象工厂子包

ObjectFactory接口

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

/**
 * MyBatis uses an ObjectFactory to create all needed new Objects.
 * MyBatis使用ObjectFactory来创建所有需要的新对象。
 * @author Clinton Begin
 */
public interface ObjectFactory {

  /**
   * Sets configuration properties.
   * 设置configuration属性。
   * @param properties
   *          configuration properties
   */
  default void setProperties(Properties properties) {
    // NOP
  }

  /**
   * Creates a new object with default constructor.
   * 使用默认构造函数创建一个新对象
   * @param <T> the generic type
   * @param type Object type
   * @return the t
   */
  <T> T create(Class<T> type);

  /**
   * Creates a new object with the specified constructor and params.
   * 用指定的构造函数和参数创建一个新对象。
   * @param <T> the generic type
   * @param type Object type
   * @param constructorArgTypes Constructor argument types
   * @param constructorArgs Constructor argument values
   * @return the t
   */
  <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs);

  /**
   * Returns true if this object can have a set of other objects. It's main purpose is to support
   * non-java.util.Collection objects like Scala collections.
   * 如果此对象可以有一组其它对象,则返回true。它的主要目的是支持非java.util.Collection对象比如Scala集合。
   * @param <T> the generic type
   * @param type Object type
   * @return whether it is a collection or not
   *
   * @since 3.1.0
   */
  <T> boolean isCollection(Class<T> type);

}
DefaultObjectFactory

DefaultObjectFactory,实现了ObjectFactory工厂接口,用于创建Class类对象。

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);
  }

  /**
   * 创建类的实例
   * @param type 要创建实例的类
   * @param constructorArgTypes 构造方法传入参数类型
   * @param constructorArgs 构造方法输入参数
   * @return
   * @param <T> 实例类型
   */
  private <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    try {
      Constructor<T> constructor; // 构造方法
      // 参数类型列表为null或者参数列表为null,即通过无参构造方法,创建指定类的对象
      if (constructorArgTypes == null || constructorArgs == null) {
        constructor = type.getDeclaredConstructor(); // 获取无参构造函数
        try {
          return constructor.newInstance(); // 使用无参构造函数创建对象
        } catch (IllegalAccessException e) {
          if (Reflector.canControlMemberAccessible()) {
            // 如果发生异常,则修改构造函数的访问属性后再次尝试
            constructor.setAccessible(true);
            return constructor.newInstance();
          }
          throw e;
        }
      }
      // 根据输入参数类型查找对应的构造器,即通过特定构造方法,创建指定类的对象
      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]));
        }
        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) {
      // 判断是否是集合,是则返回List对象
      classToCreate = ArrayList.class;
    } else if (type == Map.class) {
      classToCreate = HashMap.class; // Map类型返回HashMap对象
    } else if (type == SortedSet.class) { // issue #510 Collections Support
      classToCreate = TreeSet.class; // SortedSet类型返回TreeSet对象
    } else if (type == Set.class) {
      classToCreate = HashSet.class; // Set类型返回HashSet对象
    } else {
      // 如果不满足以上类型,直接返回原对象
      classToCreate = type;
    }
    return classToCreate;
  }

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

}

② 执行器子包

reflection包下的invoker子包是执行器子包,该子包中的类能够基于反射实现对象方法的调用和对象属性的读写。

Invoker接口

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

public interface Invoker {
  // 执行Field或者Method
  Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException;

  // 返回属性相应的属性
  Class<?> getType();
}
  • invoker方法:即执行方法。该方法负责完成对象方法的调用和对象属性的读写。在三个实现类中,分别是属性读取操作、属性赋值操作、方法触发操作。
  • getType方法:用来获取类型。它对于 GetFieldInvoker和 SetFieldInvoker的含义也是明确的,即获得目标属性的类型。对于MethodInvoker则是直接返回type属性。

该接口有三个实现:

在这里插入图片描述

Invoker接口的三个实现类分别用来处理三种不同的情况:

  • GetFieldInvoker:负责对象属性的读操作
  • SetFieldInvoker:负责对象属性的写操作
  • MethodInvoker:负责对象其他方法的操作
MethodInvoker

Class类中属性对应set方法或者get方法的封装。

public class MethodInvoker implements Invoker {

  private final Class<?> type; // 类型
  private final Method method; // 指定方法

  public MethodInvoker(Method method) {
    this.method = method;
    // 获取属性类型
    if (method.getParameterTypes().length == 1) {
      // 如果方法有且只有一个输入参数,type为输入参数类型,即setter方法。
      type = method.getParameterTypes()[0];
    } else {
      // 否则,type为方法返回值的类型,即getter方法。
      type = method.getReturnType();
    }
  }
  
  @Override
  public Object invoke(Object target, Object[] args) throws IllegalAccessException, InvocationTargetException {
    try {
      return method.invoke(target, args); // 通过调用method.invoke()执行目标对象方法
    } catch (IllegalAccessException e) {
      if (Reflector.canControlMemberAccessible()) {
        method.setAccessible(true);
        return method.invoke(target, args);
      }
      throw e;
    }
  }

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

MethodInvoker在其构造函数中,设置set方法或者get方法,并获取其参数类型或者返回值类型进行保存。

SetFieldInvoker & GetFieldInvoker

没有getter/setter方法的属性,使用GetFieldInvokerSetFieldInvoker 封装了属性对应的Field对象,通过调用Field.get()/set()实现获取设置属性值。

public class GetFieldInvoker implements Invoker {
  private final Field field; // 属性对应的Field对象
  public GetFieldInvoker(Field field) {
    this.field = field;
  }

  /**
   * 代理方法,获取目标对象的属性值。
   * @param target 被代理的目标对象
   * @param args 方法的参数
   * @return 方法执行结果
   * @throws IllegalAccessException
   */
  @Override
  public Object invoke(Object target, Object[] args) throws IllegalAccessException {
    try {
      return field.get(target); // 直接通过反射获取目标属性值
    } catch (IllegalAccessException e) {
      if (Reflector.canControlMemberAccessible()) {
        // 如果无法访问,修改属性的访问属性
        field.setAccessible(true); // 将属性的可访问性修改为可访问
        return field.get(target); // 再次通过反射获取目标属性的值
      }
      throw e;
    }
  }
  // 获取属性类型
  @Override
  public Class<?> getType() {
    return field.getType();
  }
}

public class SetFieldInvoker implements Invoker {
  private final Field field; // 属性对应的Field对象
  public SetFieldInvoker(Field field) {
    this.field = field;
  }

  /**
   * 代理方法,设置目标对象的属性值
   * @param target 被代理的目标对象
   * @param args 方法的参数
   * @return
   * @throws IllegalAccessException
   */
  @Override
  public Object invoke(Object target, Object[] args) throws IllegalAccessException {
    try {
      field.set(target, args[0]); // 设置属性值
    } catch (IllegalAccessException e) {
      // 如果无法访问
      if (!Reflector.canControlMemberAccessible()) {
        // 如果不能访问控制成员,则抛出异常
        throw e;
      }
      // 如果可以,则修改属性的访问属性
      field.setAccessible(true);
      // 再次设置目标属性的值
      field.set(target, args[0]);
    }
    return null;
  }
  // 获取属性类型
  @Override
  public Class<?> getType() {
    return field.getType();
  }
}

③ 属性子包

reflection包下的property子包是属性子包,该子包中的类用来完成与对象属性相关的操作。

  • PropertyCopier:主要用于两个对象之间的复制。
  • PropertyNamer:主要用于完成属性名和方法名之间的转化。
  • PropertyTokenizer:主要用于解析表达式,比如mapper.xml中的动态sql。
PropertyCopier

PropertyCopier作为属性复制器,就是用来解决上述问题的,借助于属性复制器PropertyCopier,我们可以方便地将一个对象属性复制到另一个对象中。

User user = new User(1L, "张三");
User copy = new User();
PropertyCopier.copyBeanProperties(user.getClass(), user, copy);

输出:
User{id=1, name='张三'}
User{id=1, name='张三'}
public final class PropertyCopier {
  private PropertyCopier() {
    // Prevent Instantiation of Static Class 阻止静态类的实例化
  }

  /**
   * 完成对象的输出复制
   * @param type 对象的类型
   * @param sourceBean 提供属性值的对象
   * @param destinationBean 要被写入新属性值的对象
   */
  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()) {
              throw e; // 如果无法访问控制成员,则抛出异常
            }
            field.setAccessible(true); // 修改属性的可访问性
            field.set(destinationBean, field.get(sourceBean)); // 再次复制属性值
          }
        } catch (Exception e) {
          // Nothing useful to do, will only fail on final fields, which will be ignored.
          // 没有做任何有用的操作,只会在final字段失败,该字段将会被忽略。
        }
      }
      parent = parent.getSuperclass();
    }
  }
}

copyBeanProperties方法的工作原理十分简单:通过反射获取类的所有属性,然后依次将这些属性值从源对象复制出来并赋给目标对象。但是要注意,该属性复制器无法完成继承得来的属性的赋值,因为getDeclalaredFields方法返回的属性中不包含继承属性。

PropertyNamer

PropertyNamer提供属性名称相关的操作功能,例如,通过get、set方法的方法名找出对应的属性等。

要想让PropertyNamer正常的发挥作用,需要被整对象书对象、方法的命名遵循Java Bean的命名规范。

即:

  • 如果类成员变量名字是abc,那么该属性对应的读写方法分别命名为getAbc()setAbc()
  • 如果类的属性是boolean类型,则允许使用is代替上面的get,读方法命名为isAbc()
public final class PropertyNamer {
  private PropertyNamer() {
    // Prevent Instantiation of Static Class 阻止静态类实例化
  }

  /**
   * 通过方法名找出对应的属性
   * @param name 方法名
   * @return 属性名
   */
  public static String methodToProperty(String name) {
    if (name.startsWith("is")) {
      name = name.substring(2); // 如果方法名以“is”开头,即boolean类型的属性,则去除“is”
    } else if (name.startsWith("get") || name.startsWith("set")) {
      name = name.substring(3); // 如果方法名以“get”或者“set”开头,则去除
    } 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))) {
      // 处理get、set方法的驼峰式命名,将首字母改为小写
      name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
    }
    return name;
  }

  public static boolean isProperty(String name) {
    return isGetter(name) || isSetter(name);
  }

  public static boolean isGetter(String name) {
    // 判断是否是getter方法命名。条件:①以get开头并且字符串长度大于3 ②以is开头并且字符串长度大于2
    return name.startsWith("get") && name.length() > 3 || name.startsWith("is") && name.length() > 2;
  }

  public static boolean isSetter(String name) {
    // 判断是否是setter方法命名。条件:以set开头并且字符串长度大于3
    return name.startsWith("set") && name.length() > 3;
  }
}
PropertyTokenizer

PropertyTokenizer是一个属性标记器,用于解析属性表达式,传入一个形如student[sId].name的字符串后,该标记器会将其拆分开,放入各个属性中。拆分结束后各个属性的值如下代码注释所示:

  private String name; // student
  private final String indexedName; // student[sId]
  private String index;  // sId
  private final String children; // name
public class PropertyTokenizer implements Iterator<PropertyTokenizer> {
  /**
   * 例如表达式 "student[sId].name",解析器的每个字段的值如下:
   *  name:student
   *  indexedName: student[sId]
   *  index:sId
   *  children:name
   */
  private String name; // 当前属性名
  private final String indexedName; // 表示带索引的属性名,如果当前无索引,则该值和name相同
  private String index; // 表示索引下标
  private final String children; // 去除name外的子表达式

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

  // getter方法...

  /**
   * hasNext()、next()、remove() 实现自Iterator接口中的方法
   */
  @Override
  public boolean hasNext() {
    return children != null;
  }

  @Override
  public PropertyTokenizer next() {
    return new PropertyTokenizer(children); // 创建下一个PropertyTokenizer对象
  }

  @Override
  public void remove() {
    throw new UnsupportedOperationException(
        "Remove is not supported, as it has no meaning in the context of properties.");
  }
}

④ 对象包装器子包

reflection包下的wrapper子包是对象包装器子包,该子包中的类使用装饰器模式对各种类型的对象(包括基本的Bean对象、集合对象、Map对象)进行进一步的封装,为其增加一些功能,使它们更易于使用。

在这里插入图片描述

ObjectWrapperFactory

ObjectWrapperFactory是对象包装器的工厂的接口,DefaultObjectWrapperFactory是它的默认实现。不过该默认实现中并没有实现任何功能。

MyBatis允许用户通过配置文件中的objectWrapperFactory节点来注入新的ObjectWrapperFactory。

/**
 * 一个对象包装器创建工厂的接口定义,负责将普通的Java对象包装成ObjectWrapper实例。
 * @author Clinton Begin
 */
public interface ObjectWrapperFactory {
  boolean hasWrapperFor(Object object); // 是否拥有指定对象的装饰对象
  ObjectWrapper getWrapperFor(MetaObject metaObject, Object object); // 通过对象元数据获取指定对象的包装对象
}
DefaultObjectWrapperFactory

ObjectWrapperFactory对象包装器工厂接口的默认实现。

/**
 * 默认的对象包装器工厂
 * @author Clinton Begin
 */
public class DefaultObjectWrapperFactory implements ObjectWrapperFactory {
  @Override
  public boolean hasWrapperFor(Object object) {
    return false;  // 是否用于指定对象的装饰对象,默认为false
  }
  @Override
  public ObjectWrapper getWrapperFor(MetaObject metaObject, Object object) {
    // 通过对象元数据获取指定对象的包装对象,默认不允许获取,直接抛出异常。
    throw new ReflectionException(
        "The DefaultObjectWrapperFactory should never be called to provide an ObjectWrapper.");
  }

}
ObjectWrapper

ObjectWrapper接口是所有对象包装器的总接口,提供统一的包装对象的属性操作规范。

/**
 * 对象包装器接口定义,包装对象后提供统一的属性操作方法
 * @author Clinton Begin
 */
public interface ObjectWrapper {
  Object get(PropertyTokenizer prop); // 获取被包装对象某个属性的值
  void set(PropertyTokenizer prop, Object value); // 设置被包装对象某个属性的值
  String findProperty(String name, boolean useCamelCaseMapping); // 查找属性名称
  String[] getGetterNames(); // 获取所有的属性get方法名称
  String[] getSetterNames(); // 获取所有的属性set方法名称
  Class<?> getSetterType(String name); // 获取指定属性的set方法的参数类型
  Class<?> getGetterType(String name); // 获取指定属性的get方法的返回类型
  boolean hasSetter(String name); // 是否有指定属性的set方法
  boolean hasGetter(String name); // 是否有指定属性的get方法

  /**
   * 实例化某个属性的值,并获取对应的MetaObject对象
   * @param name 完整的属性名
   * @param prop 属性名描述符
   * @param objectFactory 对象创建工厂
   * @return 指定的属性的值对应的MetaObject对象
   */
  MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory);
  boolean isCollection(); // 判断被包装的对象是否是集合
  void add(Object element); // 往被包装的集合对象中添加新的元素 
  <E> void addAll(List<E> element); // 往被包装的集合对象中添加一组元素
}

因为不同的Java对象,其属性操作方法也有所不同,所以MyBatis默认为ObjectWrapper提供了四个实现类:

  • BaseWrapper:抽象类,为子类BeanWrapper和MapWrapper提供公共的方法和属性。
  • BeanWrapper:普通对象的包装器实现类,处理User这样的实体类。
  • MapWrapper:是对Map接口子类的包装。
  • CollectionWrapper:是对集合对象的包装。

在这里插入图片描述

BaseWrapper

BaseWrapper是ObjectWrapper接口的抽象实现,用于定义公共逻辑的处理方法。使用了模板设计模式。

/**
 * 基础包装器,实现ObjectWrapper接口。
 * 为子类BeanWrapper和MapWrapper提供公共的方法和属性。
 * @author Clinton Begin
 */
public abstract class BaseWrapper implements ObjectWrapper {
  protected static final Object[] NO_ARGUMENTS = {}; // 无参,主要用于执行get方法所需
  protected final MetaObject metaObject; // 被包装对象的元数据对象
  protected BaseWrapper(MetaObject metaObject) {
    this.metaObject = metaObject;
  }

  /**
   * 解析对象中的集合名
   * 根据属性表达式获取对应属性的集合(Array、List、Map)对象,调用MetaObject的getValue()方法获取。
   * @param prop PropertyTokenizer对象
   * @param object 指定Object对象
   * @return
   */
  protected Object resolveCollection(PropertyTokenizer prop, Object object) {
    if ("".equals(prop.getName())) {
      // 如果表达式不合法解析不到属性名,则直接返回默认值
      return object;
    }
    // 解析到属性名,调用metaObject.getValue()方法获取属性值并返回
    return metaObject.getValue(prop.getName());
  }

  /**
   * 根据属性表达式获取集合(Array、List、Map)的值
   * @param prop  PropertyTokenizer对象
   * @param collection 集合(Array、List、Map)
   * @return 对应下标或key的值
   */
  protected Object getCollectionValue(PropertyTokenizer prop, Object collection) {
    if (collection instanceof Map) {
      return ((Map) collection).get(prop.getIndex()); // 如果是Map类型,则index为key
    }
    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[]) {
      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.");
    }
  }

  /**
   * 根据(参数prop)设置集合(Array、List、Map)的值
   * @param prop
   * @param collection
   * @param value
   */
  protected void setCollectionValue(PropertyTokenizer prop, Object collection, Object value) {
    if (collection instanceof Map) {
      ((Map) collection).put(prop.getIndex(), value); // 如果是Map类型,则index为key
    } else {
      int i = Integer.parseInt(prop.getIndex());
      // 如果是其他类型,则index为下标
      if (collection instanceof List) {
        ((List) collection).set(i, value);
      } else if (collection instanceof Object[]) {
        ((Object[]) collection)[i] = value;
      } else if (collection instanceof char[]) {
        ((char[]) collection)[i] = (Character) value;
      } else if (collection instanceof boolean[]) {
        ((boolean[]) collection)[i] = (Boolean) value;
      } else if (collection instanceof byte[]) {
        ((byte[]) collection)[i] = (Byte) value;
      } else if (collection instanceof double[]) {
        ((double[]) collection)[i] = (Double) value;
      } else if (collection instanceof float[]) {
        ((float[]) collection)[i] = (Float) value;
      } else if (collection instanceof int[]) {
        ((int[]) collection)[i] = (Integer) value;
      } else if (collection instanceof long[]) {
        ((long[]) collection)[i] = (Long) value;
      } else if (collection instanceof short[]) {
        ((short[]) collection)[i] = (Short) value;
      } else {
        // 不是集合类型,则抛出异常
        throw new ReflectionException(
            "The '" + prop.getName() + "' property of " + collection + " is not a List or Array.");
      }
    }
  }
}
BeanWrapper
/**
 * 普通对象包装器
 * 继承BaseWrapper类,基于MetaClass实现Object的属性操作。
 * @author Clinton Begin
 */
public class BeanWrapper extends BaseWrapper {
  private final Object object; // 被包装的对象
  private final MetaClass metaClass; // 被包装对象所属类的元类
  public BeanWrapper(MetaObject metaObject, Object object) {
    super(metaObject);
    this.object = object;
    this.metaClass = MetaClass.forClass(object.getClass(), metaObject.getReflectorFactory());
  }

  /**
   * 获取被包装对象中对应表达式的属性值
   * @param prop 属性表达式,注意,该表达式不包含子表达式
   * @return
   *
   * 如果表达式形如:`arr[0]/list[0]/map[key]`,则先获取对应属性`arr/list/map`对象的值,再获取索引对应元素的值。
   * 如果表达式不带索引,则传入的就是个属性名,调用`getBeanProperty`方法,获取属性对应的值。
   */
  @Override
  public Object get(PropertyTokenizer prop) {
    if (prop.getIndex() != null) {
      // 若存在索引信息,则表示该属性表达式中的name部分为集合属性
      // 通过BaseWrapper中的公共方法resolveCollection获取集合对象和集合属性
      Object collection = resolveCollection(prop, object);
      return getCollectionValue(prop, collection);
    }
    // 不存在索引信息,则name部分为普通对象,查找并调用Invoker相关方法获取属性
    return getBeanProperty(prop, object);
  }

  @Override
  public void set(PropertyTokenizer prop, Object value) {
    if (prop.getIndex() != null) {
      // 若存在索引信息,则表示该属性表达式中的name部分为集合属性
      // 通过BaseWrapper中的公共方法resolveCollection获取集合对象和集合属性
      Object collection = resolveCollection(prop, object);
      setCollectionValue(prop, collection, value);
    } else {
      // 不存在索引信息,则name部分为普通对象,查找并调用Invoker相关方法设置属性
      setBeanProperty(prop, object, value);
    }
  }

  @Override
  public String findProperty(String name, boolean useCamelCaseMapping) {
    return metaClass.findProperty(name, useCamelCaseMapping);
  }

  @Override
  public String[] getGetterNames() {
    return metaClass.getGetterNames();
  }

  @Override
  public String[] getSetterNames() {
    return metaClass.getSetterNames();
  }

  @Override
  public Class<?> getSetterType(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name); // 解析表达式
    if (!prop.hasNext()) {
      // 不存在子表达式,直接调用metaClass.getSetterType()方法获取属性类型
      // 这里之所以是使用metaClass.getSetterType(name)而不是metaValue.getSetterType(name)
      // 是因为metaValue.getSetterType也是依赖objectWrapper.getSetterType,如果还是调用
      // metaValue.getSetterType会陷入无限递归,metaClass才是递归的出口
      return metaClass.getSetterType(name);
    }
    // 创建MetaObject对象
    // 为什么优先使用MetaObject?而当且仅当封装的对象为空时,才使用MetaClass对象呢?
    // MetaClass封装的是类的元信息,MetaObject封装的是对象的元信息,可以将类的元信息看成是对象元信息的一个子集。
    // 根据类元信息得到的一些类型信息可能更加具体。
    MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
    if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
      // 如果metaValue为SystemMetaObject.NULL_META_OBJECT,表示封装的Java对象值为null
      // 通过类元信息,获取set方法对应属性类型
      return metaClass.getSetterType(name);
    } else {
      // 当对象不为空时,通过对象元信息,获取set方法对应属性类型,可以获得更具体的类型信息
      // 递归判断子表达式的children。然后返回。
      return metaValue.getSetterType(prop.getChildren());
    }
  }

  /**
   * 获取属性表达式对应的属性的get方法的返回类型
   * @param name
   * @return
   */
  @Override
  public Class<?> getGetterType(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (!prop.hasNext()) {
      return metaClass.getGetterType(name);
    }
    MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
    if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
      return metaClass.getGetterType(name);
    } else {
      return metaValue.getGetterType(prop.getChildren());
    }
  }

  /**
   * 是否存在属性表达式对应的属性的set方法
   * @param name
   * @return
   */
  @Override
  public boolean hasSetter(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (!prop.hasNext()) {
      return metaClass.hasSetter(name);
    }
    if (metaClass.hasSetter(prop.getIndexedName())) {
      MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        return metaClass.hasSetter(name);
      } else {
        return metaValue.hasSetter(prop.getChildren());
      }
    } else {
      return false;
    }
  }

  /**
   * 是否存在表达式对应的属性的get方法 
   * @param name
   * @return
   */
  @Override
  public boolean hasGetter(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (!prop.hasNext()) {
      return metaClass.hasGetter(name);
    }
    if (metaClass.hasGetter(prop.getIndexedName())) {
      MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        return metaClass.hasGetter(name);
      } else {
        return metaValue.hasGetter(prop.getChildren());
      }
    } else {
      return false;
    }
  }

  /**
   * 为表达式指定的属性创建对应的MetaObject对象
   * @param name 完整的属性名
   * @param prop 属性名描述符
   * @param objectFactory 对象创建工厂
   * @return
   */
  @Override
  public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {
    MetaObject metaValue;
    Class<?> type = getSetterType(prop.getName()); // 获取属性表达式指定属性的类型 
    try {
      Object newObject = objectFactory.create(type); // 创建对应的属性对象 
      // 创建属性对应的MetaObject对象
      metaValue = MetaObject.forObject(newObject, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory(),
          metaObject.getReflectorFactory());
      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;
  }

  private Object getBeanProperty(PropertyTokenizer prop, Object object) {
    try {
      // 得到获取属性对应的Invoker对象
      Invoker method = metaClass.getGetInvoker(prop.getName());
      try {
        return method.invoke(object, NO_ARGUMENTS); // 通过Invoker封装的反射操作获取属性值
      } 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);
    }
  }

  private void setBeanProperty(PropertyTokenizer prop, Object object, Object value) {
    try {
      Invoker method = metaClass.getSetInvoker(prop.getName());
      Object[] params = { value };
      try {
        method.invoke(object, params);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    } catch (Throwable t) {
      throw new ReflectionException("Could not set property '" + prop.getName() + "' of '" + object.getClass()
          + "' with value '" + value + "' Cause: " + t.toString(), t);
    }
  }

  @Override
  public boolean isCollection() {
    return false;
  }

  @Override
  public void add(Object element) {
    throw new UnsupportedOperationException();
  }

  @Override
  public <E> void addAll(List<E> list) {
    throw new UnsupportedOperationException();
  }
}
MapWrapper
/**
 * Map对象包装器
 * 继承BaseWrapper类,基于Map接口方法实现对属性的操作。
 * @author Clinton Begin
 */
public class MapWrapper extends BaseWrapper {

  private final Map<String, Object> map; // 封装的Map对象

  public MapWrapper(MetaObject metaObject, Map<String, Object> map) {
    super(metaObject);
    this.map = map;
  }

  @Override
  public Object get(PropertyTokenizer prop) {
    if (prop.getIndex() != null) {
      // 存在索引信息,则表示该属性表达式中的name部分为集合属性
      Object collection = resolveCollection(prop, map);
      return getCollectionValue(prop, collection);
    }
    // 不存在索引信息,则name部分为普通对象,直接从map中获取值
    return map.get(prop.getName());
  }

  @Override
  public void set(PropertyTokenizer prop, Object value) {
    if (prop.getIndex() != null) {
      // 存在索引信息,则表示该属性表达式中的name部分为集合属性
      Object collection = resolveCollection(prop, map);
      setCollectionValue(prop, collection, value);
    } else {
      // 不存在索引信息,则name部分为普通对象,直接从map中设置值
      map.put(prop.getName(), value);
    }
  }

  @Override
  public String findProperty(String name, boolean useCamelCaseMapping) {
    return name;
  }

  @Override
  public String[] getGetterNames() {
    return map.keySet().toArray(new String[0]);
  }

  @Override
  public String[] getSetterNames() {
    return map.keySet().toArray(new String[0]);
  }

  @Override
  public Class<?> getSetterType(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name); // 根据属性表达式创建PropertyTokenizer对象
    if (prop.hasNext()) {
      // 如果存在子表达式,根据indexedName创建MetaObject对象
      MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        return Object.class; // 如果对应的属性为null,直接返回Object类型
      } else {
        // 否则子表达式由MetaObject处理
        return metaValue.getSetterType(prop.getChildren());
      }
    }
    // 没有子表达式,直接map操作
    if (map.get(name) != null) {
      return map.get(name).getClass();
    } else {
      return Object.class;
    }
  }

  @Override
  public Class<?> getGetterType(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (prop.hasNext()) {
      MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        return Object.class;
      } else {
        return metaValue.getGetterType(prop.getChildren());
      }
    }
    if (map.get(name) != null) {
      return map.get(name).getClass();
    } else {
      return Object.class;
    }
  }

  @Override
  public boolean hasSetter(String name) {
    return true;
  }

  @Override
  public boolean hasGetter(String name) {
    PropertyTokenizer prop = new PropertyTokenizer(name);
    if (!prop.hasNext()) {
      return map.containsKey(prop.getName());
    }
    if (map.containsKey(prop.getIndexedName())) {
      MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
      if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
        return true;
      } else {
        return metaValue.hasGetter(prop.getChildren());
      }
    } else {
      return false;
    }
  }

  /**
   * 针对嵌套属性的场景
   * @param name 完整的属性名
   * @param prop 属性名描述符
   * @param objectFactory 对象创建工厂
   * @return
   *
   * 如:person.name 首次设置person会创建一个key为person,value为new HashMap<>()
   */
  @Override
  public MetaObject instantiatePropertyValue(String name, PropertyTokenizer prop, ObjectFactory objectFactory) {
    HashMap<String, Object> map = new HashMap<>();
    set(prop, map);
    return MetaObject.forObject(map, metaObject.getObjectFactory(), metaObject.getObjectWrapperFactory(),
        metaObject.getReflectorFactory());
  }

  @Override
  public boolean isCollection() {
    return false;
  }

  @Override
  public void add(Object element) {
    throw new UnsupportedOperationException();
  }

  @Override
  public <E> void addAll(List<E> element) {
    throw new UnsupportedOperationException();
  }

}
CollectionWrapper

集合包装器源码比较简单,这里不再介绍。

⑤ 反射核心类

reflection包中最为核心的类就是Reflector类。

在这里插入图片描述

Reflector

MyBatis提供Reflector类来缓存类的字段名和getter/setter方法的元信息,使得涉及反射的操作不再去获取这些元信息,使操作更加便捷,使用方式是将原始类对象Class传入其构造方法,生成Reflector对象。

Reflector将一个类反射解析后,会将该类的属性、方法等一一归类放到各个属性集合中。

public class Reflector {

  private static final MethodHandle isRecordMethodHandle = getIsRecordMethodHandle();
  private final Class<?> type; // 对应的class类型
  private final String[] readablePropertyNames; // 可读属性的名称集合,可读属性就是存在get方法的属性,初始值为null
  private final String[] writablePropertyNames; // 可写属性的名称集合,可写属性就是存在set方法的属性,初始值为null
  private final Map<String, Invoker> setMethods = new HashMap<>(); // 属性对应的set方法,key是属性名称,value是对应的set方法
  private final Map<String, Invoker> getMethods = new HashMap<>(); // 属性对应的get方法,key是属性名称,value是对应的get方法
  // set方法输入类型。key是属性名,值为对应的该属性的set方法的类型(实际为set方法的第一个参数的类型)
  private final Map<String, Class<?>> setTypes = new HashMap<>();
  // get方法输出类型。key是属性名,值为对应的该属性的get方法的类型(实际为get方法的返回值类型)
  private final Map<String, Class<?>> getTypes = new HashMap<>();
  private Constructor<?> defaultConstructor; // 默认的构造方法

  private final Map<String, String> caseInsensitivePropertyMap = new HashMap<>(); // 所有属性名称的集合,key为大写的属性名称,value为属性名称

  /**
   * 解析在指定的Class类型,并填充上述的集合的属性,即初始化相关字段
   * @param clazz
   */
  public Reflector(Class<?> clazz) {
    type = clazz; // 初始化type字段
    addDefaultConstructor(clazz); // 设置默认的构造方法,默认无参,具体实现是通过反射遍历所有的构造方法
    Method[] classMethods = getClassMethods(clazz); // 获取类的所有方法
    // 判断Class是不是record类型
    if (isRecord(type)) {
      addRecordGetMethods(classMethods);
    } else {
      addGetMethods(classMethods); // 处理所有方法中的getter方法,填充getMethods集合和getTypes接口
      addSetMethods(classMethods); // 处理所有方法中的setter方法,填充setMethods集合和setTypes接口
      addFields(clazz); // 处理没有getter和setter方法的字段
    }
    // 初始化为空数组
    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在初始化的时候会通过反射机制进行解析该类,整个解析的过程并不复杂。

  • Reflector的构造函数中,会解析指定的Class对象,并填充上述集合。
  • Reflector.addGetMethods()方法主要解析类中定义的getter方法
  • Reflector.addSetMethods()方法主要解析类中定义的Setter方法。

下面以addGetMethods()方法为例进行介绍。

private void addGetMethods(Method[] methods) {
    Map<String, List<Method>> conflictingGetters = new HashMap<>();
    // 使用Java8的stream从所有方法中找出符合以下条件的方法:(1)方法参数长度为0,即无参方法 (2)符合getter方法命名规范(以get开头且方法名长度大于3 或者 以is开头且方法名长度大于2)
    Arrays.stream(methods).filter(m -> m.getParameterTypes().length == 0 && PropertyNamer.isGetter(m.getName()))
        .forEach(m -> addMethodConflict(conflictingGetters, PropertyNamer.methodToProperty(m.getName()), m)); // 记录方法参数类型、返回值等信息
    resolveGetterConflicts(conflictingGetters); // 处理重复方法名。注意:一个key会有多个method的原因是:当子类覆盖了父类的getter方法并且返回值发生变化时,会产生两个签名不同的方法。
  }

addGetMethods方法主要用于处理clazz的所有方法中的getter方法,并填充getMethods集合和getTypes集合。

  • addMethodConflict()方法,主要用来获取字段名和字段名对应的getter方法的映射集合,并把结果保存到conflictingGetters变量中;
  • resolveGetterConflicts()方法,主要用来处理方法名重复的方法。

下面简单看一下 resolveGetterConflicts()方法是如何去重的:

private void resolveGetterConflicts(Map<String, List<Method>> 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;
      }
      // 字段对应多个get方法 
      Class<?> winnerType = winner.getReturnType();
      Class<?> candidateType = candidate.getReturnType();
      if (candidateType.equals(winnerType)) { // 返回值类型相同
        if (!boolean.class.equals(candidateType)) {
          isAmbiguous = true;
          break;
        }
        if (candidate.getName().startsWith("is")) {
          winner = candidate; // 返回值为boolean的get方法可能有多个,如getIsSave()和isSave(),优先使用is开头的、更规范的方法
        }
      } else if (candidateType.isAssignableFrom(winnerType)) {
        // OK getter type is descendant getter类型是后代,比如接口中方法的返回值是List类型,子类实现方法的返回值是ArrayList,这时会使用子类返回的方法。
      } else if (winnerType.isAssignableFrom(candidateType)) {
        winner = candidate;
      } else {
        isAmbiguous = true;
        break;
      }
    }
    addGetMethod(propName, winner, isAmbiguous); // 记录字段名对应的get方法对象和返回值类型
  }
}

去重的方式是使用更加规范的方法以及使用子类的返回值类型的方法。在确认字段名对应的唯一 getter/setter 方法后,记录方法名对应的方法、参数、返回值等信息。

另外,Reflector中还提供了一些公共的API方法,如下表格:

方法名称作用
getType获取Reflector表示的Class
getDefaultConstructor获取默认的构造器
hasDefaultConstructor判断是否有默认的构造器
getSetInvoker根据属性名称获取对应的Invoker 对象
getGetInvoker根据属性名称获取对应的Invoker对象
getSetterType获取属性对应的类型 比如:
String name; // getSetterType(“name”) --> java.lang.String
getGetterType获取属性对应的类型
getGetablePropertyNames获取所有的可读属性名称的集合
getSetablePropertyNames获取所有的可写属性名称的集合
hasSetter判断是否具有某个可写的属性
hasGetter判断是否具有某个可读的属性
findPropertyName根据名称查找属性
ReflectorFactory

ReflectorFactory是Reflector的工厂接口,而DefaultReflectorFactory是该工厂接口的默认实现。

ReflectorFactory接口主要实现了对Reflector对象的创建和缓存

public interface ReflectorFactory {
  boolean isClassCacheEnabled(); // 检测该ReflectorFactory是否缓存了Reflector对象
  void setClassCacheEnabled(boolean classCacheEnabled); // 设置是否缓存Reflector对象
  Reflector findForClass(Class<?> type); // 创建指定了Class的Reflector对象
}

具体是实现类图如下:

在这里插入图片描述

MyBatis只为该接口提供了DefaultReflectorFactory这一个实现类。

DefaultReflectorFactory

代码比较简单,主要是根据Class对象创建Reflector对象。

public class DefaultReflectorFactory implements ReflectorFactory {
  private boolean classCacheEnabled = true; // 该字段决定是否开启对Reflector对象的缓存
  private final ConcurrentMap<Class<?>, Reflector> reflectorMap = new ConcurrentHashMap<>(); // 目标类和反射器映射缓存

  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) { // classCacheEnabled默认为true
      // synchronized (type) removed see issue #461
      // 从缓存中获取Reflector对象,如果缓存为空,则创建一个新的实例,放入缓存中
      return MapUtil.computeIfAbsent(reflectorMap, type, Reflector::new);
    }
    return new Reflector(type); // 创建一个新的Reflector实例
  }

}

⑥ 反射包装类

reflection包中存在许多的包装类,它们使用装饰器模式将许多反射相关的类包装的更加简单易用。

下面介绍两个更为基础的包装类:MetaClass类和MetaObject类。

MetaObject

MetaObject被称为元对象,是一个针对普通Object对象的反射包装类。

public class MetaObject {

  private final Object originalObject; // 被包装的对象的原始对象
  private final ObjectWrapper objectWrapper; // 原始对象的包装器
  private final ObjectFactory objectFactory; // 实例化对象的工厂
  private final ObjectWrapperFactory objectWrapperFactory; // 创建对象包装器的工厂
  private final ReflectorFactory reflectorFactory; // 创建Reflector对象的反射工厂

  private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory,
      ReflectorFactory reflectorFactory) {
    this.originalObject = object; // 初始化被包装对象的原始对象
    this.objectFactory = objectFactory; // 初始化实例对象的工厂类
    this.objectWrapperFactory = objectWrapperFactory; // 初始化创建对象包装器的工厂类
    this.reflectorFactory = reflectorFactory; // 初始化用于获取类描述对象的工厂类
    // 为原始对象创建对象包装器
    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);
    }
  }
 ...
}
MetaClass

Class类的元数据,包装Reflector,基于PropertyTokenizer(分词器)提供对Class类的元数据各种操作,可以理解成对Reflector操作的进一步增强

其中包含了ReflectorFactory和Reflector两个字段,通过PropertyTokenizer分词器提供了获取属性的名称和返回值类型等等方法,也就是在Reflector上面新增了一些方法。

在Reflector中可以针对对普通属性的操作,但是如果出现了比较复杂的属性,比如private Person person;这种,我们要查找的表达式person.userName。针对这种表达式的处理,我们就可以使用MetaClass来处理了。

public class MetaClass {
  private final ReflectorFactory reflectorFactory; // Reflector的工厂类,具有缓存Reflector对象的功能
  private final Reflector reflector; // 反射器,用于解析和存储目标类中的元信息。创建MetaClass时,会指定一个Class reflector会记录该类的相关信息

  private MetaClass(Class<?> type, ReflectorFactory reflectorFactory) {
    this.reflectorFactory = reflectorFactory;
    this.reflector = reflectorFactory.findForClass(type); // <settings>标签解析 根据类型创建Reflector
  }

  public static MetaClass forClass(Class<?> type, ReflectorFactory reflectorFactory) {
    return new MetaClass(type, reflectorFactory); // <settings>标签解析 调用构造方法
  }
  ...
}  
SystemMetaObject

SystemMetaObject系统级的MetaObject,限定了一些默认值。

public final class SystemMetaObject {
  // DefaultObjectFactory的单例
  public static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
  // DefaultObjectWrapperFactory的单例
  public static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
  // 空对象的MetaObject对象单例
  public static final MetaObject NULL_META_OBJECT = MetaObject.forObject(new NullObject(), DEFAULT_OBJECT_FACTORY,
      DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());

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

  private static class NullObject {
  }

  /**
   * 创建MetaObject对象
   * @param object 指定对象
   * @return MetaObject对象
   */
  public static MetaObject forObject(Object object) {
    return MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY,
        new DefaultReflectorFactory());
  }
}

⑦ 异常拆包工具

ExceptionUtil

ExceptionUtil是一个异常工具类,它提供一个拆包异常的工具方法unwrapThrowable。

该方法将InvocationTargetException和UndeclaredThrowableException这两类异常进行拆包,得到其中包含的真正的异常。

public class ExceptionUtil {
  private ExceptionUtil() {
    // Prevent Instantiation
  }

  /**
   * 拆解InvocationTargetException和UndeclaredThrowableException异常的包装,从而得到被包装的真正异常。
   * @param wrapped 包装后的异常 
   * @return 拆解出的被包装异常 
   */
  public static Throwable unwrapThrowable(Throwable wrapped) {
    Throwable unwrapped = wrapped; // 存放拆包得到的异常 
    while (true) {
      if (unwrapped instanceof InvocationTargetException) {
        // 拆包获得内部异常 
        unwrapped = ((InvocationTargetException) unwrapped).getTargetException();
      } else if (unwrapped instanceof UndeclaredThrowableException) {
        // 拆包获得内部异常
        unwrapped = ((UndeclaredThrowableException) unwrapped).getUndeclaredThrowable();
      } else {
        return unwrapped; // 其他异常无需拆包
      }
    }
  }
}

unwrapThrowable方法的结构非常简单。但是我们需要思考一下,为什么单独给这两个类拆包呢?

下面我们看一看InvocationTargetException和UndeclaredThrowableException的源码。

InvocationTargetException为必检异常,UndeclaredThrowableException为免检的运行时异常。它们都不需要MyBatis,而是来自java.lang.reflect包。

InvocationTargetException

反射操作中,代理类通过反射调用目标类的方法时,目标类的方法可能抛出异常。发射可以调用各种目标方法,因此目标方法抛出的异常是多种多样无法确定的。这意味着反射操作可能抛出一个任意类型的异常。可以使用Throwable去接收这个异常,但这无疑太过宽泛。

InvocationTargetException就是为解决这个问题而设计的,当反射操作的目标方法中出现异常时,都统一包装成一个必检异常InvocationTargetException。

InvocationTargetException内部的target则保存了原始的异常。这样一来,使得反射操作中的异常更加容易管理。

public class InvocationTargetException extends ReflectiveOperationException {

    private static final long serialVersionUID = 4085088731926701167L;
    private Throwable target; // 用来保存被包装的异常

    protected InvocationTargetException() {
        super((Throwable)null);  // Disallow initCause
    }
  /**
   * 构造方法
   * @param target 被包装的异常 
   * @return 异常的详细信息 
   */
    public InvocationTargetException(Throwable target) {
        super((Throwable)null);  // Disallow initCause
        this.target = target;
    }
    ...
}
UndeclaredThrowableException

根据Java的继承原则,我们知道:如果子类中要重写父类中的方法,那么子类方法中抛出的必检异常必须是父类方法中声明过的类型。

在建立目标类的代理类时,通常时建立了目标类接口的子类或者目标类的子类。因此,将Java的继承原则放在代理类和被代理类上可以演化为:

  • 如果代理类和被代理类实现了共同的接口,则代理方法中抛出的必检异常必须是在共同接口中声明过的;
  • 如果代理类是被代理类的子类,则代理类方法中抛出的必检异常必须是在被代理类的方法中声明过的。

可是在代理类中难免会在执行某些方法时抛出一些共同接口或者父类方法中没有声明的必检异常。那该怎么解决呢?

  • 如果不抛出,但是它是必检异常,必须抛出;
  • 如果抛出,则父接口或者父类中没有声明该必检异常,不能抛出。

答案就是这些必检异常会被包装为免检异常 UndeclaredThrowabl eException 后抛出。

public class UndeclaredThrowableException extends RuntimeException {
    static final long serialVersionUID = 330127114055056639L;
    private Throwable undeclaredThrowable; // 被包装的必检异常
    public UndeclaredThrowableException(Throwable undeclaredThrowable) {
        super((Throwable) null);  // Disallow initCause
        this.undeclaredThrowable = undeclaredThrowable;
    }

    /**
     * 构造方法 
     * @param   undeclaredThrowable  被包装的必检异常
     * @param   s 异常的详细信息
     */
    public UndeclaredThrowableException(Throwable undeclaredThrowable,
                                        String s)
    {
        super(s, null);  // Disallow initCause
        this.undeclaredThrowable = undeclaredThrowable;
    }
    ...
}

总之,InvocationTargetException 和 UndeclaredThrowableExc eption 这两个类都是异常包装类,需要拆包后才能得到真正的异常类。而 ExceptionUtil的 unwrapThrowable方法就可以完成该拆包工 作。

⑧ 参数名解析器

ParamNameResolver 是一个参数名解析器,用来按顺序列出方法 中的虚参,并对实参进行名称标注。

/**
 * 参数名解析器
 */
public class ParamNameResolver {

  public static final String GENERIC_NAME_PREFIX = "param"; // 自动生成的参数名前缀
  private final boolean useActualParamName; // 是否使用实际的参数名(通过反射获取)

  /**
   * key是索引,value是参数名称。如果指定@Param,则从@Param中获取。当不指定时,将使用参数索引。
   * 请注意:当方法具有特殊参数RowBounds或者ResultHandler时,该索引可能与实际索引不同。
   */
  // 方法输入参数的参数次序表。key为参数次序,value为参数名称或者参数@Param注解的值
  private final SortedMap<Integer, String> names;
  // 该方法输入参数中是否还有@Param注解
  private boolean hasParamAnnotation;

  /**
   * 构造方法
   * 将目标方法的参数名依次列举出来。在列举的过程中,如果某个参数存在@Param注解,则会用注解的value替换参数名。
   * (1)优先获取@Param注解的value
   * (2)通过反射获取参数名
   * (3)使用参数下标
   * @param config
   * @param method
   */
  public ParamNameResolver(Configuration config, Method method) {
    // 从配置对象中获取:是否使用实际参数名称 <setting name="useActualParamName" value="true" /> 配置
    this.useActualParamName = config.isUseActualParamName();
    // 反射获取方法参数类型
    final Class<?>[] paramTypes = method.getParameterTypes();
    // 反射获取参数注解
    final Annotation[][] paramAnnotations = method.getParameterAnnotations();
    // key为参数次序,value为参数名称,存放参数的map容器
    final SortedMap<Integer, String> map = new TreeMap<>();
    int paramCount = paramAnnotations.length;
    // get names from @Param annotations
    for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
      if (isSpecialParameter(paramTypes[paramIndex])) {
        // skip special parameters 跳过特殊参数
        /**
         * 跳过RowBounds和ResultHandler参数,这两个参数不做解析
         * RowBounds:处理分页 ResultHandler:处理结果
         */
        continue;
      }
      String name = null;
      for (Annotation annotation : paramAnnotations[paramIndex]) {
        if (annotation instanceof Param) {
          hasParamAnnotation = true;
          // 如果加了@Param注解,则使用value中指定的值
          name = ((Param) annotation).value();
          break;
        }
      }
      if (name == null) {
        // @Param was not specified. 没有使用@Param驻俄籍
        if (useActualParamName) {
          // 如果使用实际的参数名,则通过反射获取参数名
          // JDK8编译类加 -parameters参数可以保留参数名称,否则得到的是arg0,arg1这种无意义的参数名
          name = getActualParamName(method, paramIndex);
        }
        if (name == null) {
          // use the parameter index as the name ("0", "1", ...)
          // gcode issue #71
          // 如果名称还是为null,则可以使用下标来获取参数:#{param1}, #{param2}..
          name = String.valueOf(map.size());
        }
      }
      map.put(paramIndex, name);
    }
    names = Collections.unmodifiableSortedMap(map); // 使其不可变
  }

  private String getActualParamName(Method method, int paramIndex) {
    return ParamNameUtil.getParamNames(method).get(paramIndex);
  }

  private static boolean isSpecialParameter(Class<?> clazz) {
    return RowBounds.class.isAssignableFrom(clazz) || ResultHandler.class.isAssignableFrom(clazz);
  }

  public String[] getNames() {
    return names.values().toArray(new String[0]);
  }

  /**
   *
   * 获取参数名对应的参数值
   * 一般是Map结构,当参数只有1个时,直接返回,xml中写任意值都可以匹配到。
   */
  public Object getNamedParams(Object[] args) {
    final int paramCount = names.size(); // 参数个数
    if (args == null || paramCount == 0) {
      return null; // 无参情况直接返回null
    }
    if (!hasParamAnnotation && paramCount == 1) {
      // 没有@Param注解且参数只有一个
      Object value = args[names.firstKey()];
      // 如果参数是集合类型,参数名会封装成 collection/list/array
      return wrapToMapIfCollection(value, useActualParamName ? names.get(names.firstKey()) : null);
    } else {
      final Map<String, Object> param = new ParamMap<>();
      int i = 0;
      for (Map.Entry<Integer, String> entry : names.entrySet()) {
        // 参数名对应实参值
        param.put(entry.getValue(), args[entry.getKey()]);
        // add generic param names (param1, param2, ...) 额外自动生成一个参数名映射:param1, param2...
        final String genericParamName = GENERIC_NAME_PREFIX + (i + 1);
        // ensure not to overwrite parameter named with @Param 确保不要覆盖以@Param命名的参数
        if (!names.containsValue(genericParamName)) {
          param.put(genericParamName, args[entry.getKey()]);
        }
        i++;
      }
      return param;
    }
  }

  /**
   * Wrap to a {@link ParamMap} if object is {@link Collection} or array.
   * 如果对象是Collection或者数组,则包装为ParamMap。
   * 如果是集合,通过Collection访问;如果是List,通过List访问,如果是数组,通过Array访问。否则,直接返回。
   */
  public static Object wrapToMapIfCollection(Object object, String actualParamName) {
    if (object instanceof Collection) {
      ParamMap<Object> map = new ParamMap<>();
      map.put("collection", object);
      if (object instanceof List) {
        map.put("list", object);
      }
      Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object));
      return map;
    }
    if (object != null && object.getClass().isArray()) {
      ParamMap<Object> map = new ParamMap<>();
      map.put("array", object);
      Optional.ofNullable(actualParamName).ifPresent(name -> map.put(name, object));
      return map;
    }
    return object;
  }

}
  • 构造方法 ParamNameResolver能够将目标方法的参数名称依次列 举出来。在列举的过程中,如果某个参数存在@Param注解,则会用注 解的 value值替换参数名。
  • 而 getNamedParams方法是在构造方法确定的 names属性和 hasPa ramAnnotation属性值的基础上,给出实参的参数名。

⑨ 泛型解析器

TypeParameterResolver类的功能是帮助MyBatis推断出属性、返回值、输入参数中泛型的具体类型。

它对外提供了三个方法:

  • resolveFieldType:解析属性的泛型
  • resolveReturnType:解析方法返回值的泛型
  • resolveParamTypes:解析方法输入参数的泛型
  • 27
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值