mybatis源码之——ParamNameResolver类

mybatis源码之——ParamNameResolver类,第1张

mybatis源码之——ParamNameResolver类 前言

了解这个类可以帮助你更深入的理解mybatis在解析Mapper方法参数时的原理。

主要属性
// 统一的参数名称前缀
public static final String GENERIC_NAME_PREFIX = "param";
// 该布尔值用于标识是否使用实际参数名称,参数没有指定@Param注解时会置为true
private final boolean useActualParamName;

// 这个字段用于保存参数名称,使用SortedMap(默认会以key的自然顺序排序)来保存。
// key是索引值,value是参数名。如果指定了@Param,则使用指定的名称,否则使用索引值。
// 不过要注意的是,当参数列表里面有一些特殊参数(如RowBounds、ResultHandler)时,索引值与实际索引值会不一样。
// aMethod(@Param("M") int a, @Param("N") int b); 对应 {{0, "M"}, {1, "N"}}
// aMethod(int a, int b); 对应 {{0, "0"}, {1, "1"}}
// aMethod(int a, RowBounds rb, int b); 对应 {{0, "0"}, {2, "1"}}
private final SortedMap names;

// 该布尔值用来标识参数是否使用了@Param注解
private boolean hasParamAnnotation;
主要方法

ParamNameResolver构造方法getNamedParams方法 ParamNameResolver构造方法

该类的构造方法做了主要的参数名称解析工作。它能够将目标方法的参数名称依次列举出来。如果存在@Param注解,就会用该注解的value值替换参数名。

// Configuration类是mybatis的核心类,保存了所有配置相关信息。
// Method是需要被解析的Mapper方法。
public ParamNameResolver(Configuration config, Method method) {
    // 将配置config对象的默认值true赋值给当前对象的useActualParamName属性。
    this.useActualParamName = config.isUseActualParamName();
    // 获取Mapper方法的参数类型,结果是一个Class对象数组。
    final Class[] paramTypes = method.getParameterTypes();
    // 获取Mapper方法的参数注解,结果是一个Annotation接口的二维数组。
    final Annotation[][] paramAnnotations = method.getParameterAnnotations();
    // 用于存储所有参数名的SortedMap对象。
    final SortedMap map = new TreeMap<>();
    // 这个值用于判断接下来
    int paramCount = paramAnnotations.length;
    for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
        // isSpecialParameter方法用于判断参数是否属于特殊参数类型
      if (isSpecialParameter(paramTypes[paramIndex])) {
          // 如果是会跳过。
        continue;
      }
       // 判断参数的注解是否是@Param,如果是会将hasParamAnnotation设为true,并将注解的value值作为参数名称
      String name = null;
      for (Annotation annotation : paramAnnotations[paramIndex]) {
        if (annotation instanceof Param) {
          hasParamAnnotation = true;
          name = ((Param) annotation).value();
          break;
        }
      }
      // 如果经过上面处理,参数名还是null,则说明当前参数没有指定@Param注解
      if (name == null) {
        if (useActualParamName) {
          // 调用getActualParamName方法获取参数的实际名称。
          name = getActualParamName(method, paramIndex);
        }
          // 如果参数名称还是为null,则将索引值作为参数名称。("0", "1", ...)
        if (name == null) {
          name = String.valueOf(map.size());
        }
      }
        // 放入结果map
      map.put(paramIndex, name);
    }
    // 最后使用Collections工具类的静态方法将结果map变为一个不可修改类型
    names = Collections.unmodifiableSortedMap(map);
  }
getNamedParams方法

该方法会将参数名和参数值对应起来,并且还会额外保存一份以param开头加参数顺序数字的值。

  public Object getNamedParams(Object[] args) {
      // 参数个数值
    final int paramCount = names.size();
      // 没有参数
    if (args == null || paramCount == 0) {
      return null;
        // 有一个参数,并且没有@Param注解。
    } else if (!hasParamAnnotation && paramCount == 1) {
      Object value = args[names.firstKey()];
        // 如果是Collection类型包装成Map类型。
      return wrapToMapIfCollection(value, useActualParamName ? names.get(0) : null);
    } else {
        // 包装成ParamMap对象。这个对象继承了HashMap,重写了get方法。
      final Map param = new ParamMap<>();
      int i = 0;
        // 将参数名作为key, 对应的参数值作为value,放入结果param对象中
      for (Map.Entry entry : names.entrySet()) {
        param.put(entry.getValue(), args[entry.getKey()]);
          // 用于添加通用的参数名称,按顺序命名(param1, param2, ...)
        final String genericParamName = GENERIC_NAME_PREFIX + (i + 1);
         // 确保不覆盖以@Param 命名的参数
        if (!names.containsValue(genericParamName)) {
          param.put(genericParamName, args[entry.getKey()]);
        }
        i++;
      }
      return param;
    }
  

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5708769.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存