聊聊mybatis的反射之对象工厂

举报
周杰伦本人 发表于 2022/07/27 14:58:19 2022/07/27
【摘要】 聊聊mybatis的反射之对象工厂 DefaultObjectFactory默认对象工厂类 property包 PropertyCopier PropertyNamer PropertyTokenizer 总结 聊聊mybatis的反射之对象工厂今天的这篇文章会给大家讲解一下Mybatis的反射模块的一个重要的概念,那就是对象工厂。ObjectFactory是对象工厂接口,mybatis可...

聊聊mybatis的反射之对象工厂

今天的这篇文章会给大家讲解一下Mybatis的反射模块的一个重要的概念,那就是对象工厂。

ObjectFactory是对象工厂接口,mybatis可以使用ObjectFactory创新需要的新的对象,默认实现类是DefaultObjectFactory,这个类主要是实现ObjectFactory接口的create方法,

DefaultObjectFactory默认对象工厂类

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 构造方法入参
   * @param <T> 实例类型
   * @return 创建的实例
   */
  private  <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    try {
      // 构造方法
      Constructor<T> constructor;
      if (constructorArgTypes == null || constructorArgs == null) { // 参数类型列表为null或者参数列表为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);
    }
  }

这一块的代码注释也非常详细,通过源码我们能看到,create()方法调用instantiateClass()方法来创建类实例,具体过程就是根据传入的参数选择不同的构造方法来进行实例化对象,如果没有传入参数就使用无参构造器,传入了参数就使用有参构造器

property包

property文件夹有三个类:PropertyCopier,PropertyNamer和PropertyTokenizer

PropertyCopier

PropertyCopier是一个工具类,主要是属性的复制,核心方法copyBeanProperties(),完成对象的输出拷贝功能

PropertyNamer

PropertyNamer类是属性名称的处理器,它的主要功能是把方法名转换为属性名,还有判断这个方法是不是getter或setter方法,

PropertyTokenizer

PropertyTokenizer是用来属性解析的,比如传入student[index].name,它能解析出student,index,student[index],name

总结

这篇文章主要介绍了ObjectFactory对象工厂接口和它的实现类DefaultObjectFactory,功能就是根据参数调用适合的构造器生成对象,主要分析了DefaultObjectFactory的create()方法的实现,然后介绍了一下property文件夹下的三个类:PropertyCopier是用来进行属性复制的工具类,PropertyNamer是属性名称处理器,主要实现将方法名转为属性名,PropertyTokenizer是属性的解析类,这些工具我们在生产的时候也经常会遇到对象属性拷贝的情景,我们可以参考这些类的实现解决这些情景。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。