了解这个类可以帮助你更深入的理解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 SortedMapgetNamedParams方法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); }
该方法会将参数名和参数值对应起来,并且还会额外保存一份以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 Mapparam = 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; }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)