Mybatis原码学习(五)还是反射工具箱

对于反射工具箱,前面学习了Reflector还有类型解析TypeParameterResolver,都是不咋好理解的,今天接着来点思维简单点的。

ObjectFactory

这是用来创建实体对象的接口。代码如下:

public interface ObjectFactory {

	//设置配置信息
  void setProperties(Properties properties);

	//通过无参构造器创建实体对象
  <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是上面接口的唯一实现方法,里面的create()方法是通过调用instantiateClass()方法实现的。

T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
    try {
      Constructor<T> constructor;
	  //通过无参构造函数创建对象
      if (constructorArgTypes == null || constructorArgs == null) {
        constructor = type.getDeclaredConstructor();
        if (!constructor.isAccessible()) {
          constructor.setAccessible(true);
        }
        return constructor.newInstance();
      }
	  //通过指定的参数列表查找构造函数,然后实例化对象。
      constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[constructorArgTypes.size()]));
      if (!constructor.isAccessible()) {
        constructor.setAccessible(true);
      }
      return constructor.newInstance(constructorArgs.toArray(new Object[constructorArgs.size()]));
    } catch (Exception e) {
      StringBuilder argTypes = new StringBuilder();
      if (constructorArgTypes != null && !constructorArgTypes.isEmpty()) {
        for (Class<?> argType : constructorArgTypes) {
          argTypes.append(argType.getSimpleName());
          argTypes.append(",");
        }
        argTypes.deleteCharAt(argTypes.length() - 1); // remove trailing ,
      }
      StringBuilder argValues = new StringBuilder();
      if (constructorArgs != null && !constructorArgs.isEmpty()) {
        for (Object argValue : constructorArgs) {
          argValues.append(String.valueOf(argValue));
          argValues.append(",");
        }
        argValues.deleteCharAt(argValues.length() - 1); // remove trailing ,
      }
      throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
    }
  }

到这里就完事了,以上这个ObjectFactory接口还可以通过自定义类去实现接口,去实现自己需要的实体类初始化等操作。比如这篇博客里面介绍的:https://blog.csdn.net/fageweiketang/article/details/80794847

Property工具集

三种属性工具类:PropertyTokenizer、PropertyNamer、PropertyCopier.
首先是PropertyTokenizer.
比如我们在xml中设置属性表达式的时候,设计了这样一条:
orders[0].items[0].name
那么对于这样的表达式,就可以使用PropertyTokenizer来解析,该类中具体字段如下:

	//当前表达式名称
  private String name;
	//当前表达式的索引名
  private String indexedName;
	//索引下标
  private String index;
	//子表达式
  private String children;

然后在PropertyTokenizer的构造方法中,就会对传入的表达式进行解析,初始化上面的字段:

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

代码的思路如下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cV96W1Uv-1591095191576)(/img/artImg/lyc021849561591094995685.jpg ‘‘图片title’’)]
特别清晰哈哈,一看就能明白,不赘述了。
然后是PropertyNamer,提供一些静态方法,完成方法名到属性名的转换(也就是把方法名中的is、get、set去掉)

  public static String methodToProperty(String name) {
    if (name.startsWith("is")) {
      name = name.substring(2);
    } else if (name.startsWith("get") || name.startsWith("set")) {
      name = name.substring(3);
    } 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)))) {
      name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
    }

    return name;
  }

PropertyCopier,和名字意义一样,是用于属性拷贝,实现相同类型的两个对象之间的属性值拷贝,主要由copyBeanProperties实现:

 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 {
          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.
        }
      }
      parent = parent.getSuperclass();
    }
  }

个人博客 http://qlumen.cn/fore

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值