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

(/≧▽≦)/~┴┴ 嗨~我叫小奥 ✨✨✨
👀👀👀 个人博客:小奥的博客
👍👍👍:个人优快云
⭐️⭐️⭐️:传送门
🍹 本人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(
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值