ParamNameResolver是一个参数名解析器,负责把方法的参数按顺序解析出来并进行标注。
1.因为设计到字符串处理,随便写一个方法进行debug跟踪
ParamNameResolver在构造器中对getUserInfo进行解析,逻辑很简单,获取该方法所有参数类型进行遍历,如果该参数上有@Param注解就获取Param中的value作为属性名,没有的话就判断配置中useActualParamName是否允许使用原始参数名,不允许就用参数顺序进行命名。最后把解析结果存到ParamNameResolver的names属性中。
// 方法入参的参数次序表。键为参数次序,值为参数名称或者参数@Param注解的值
private final SortedMap<Integer, String> names;
// 该方法入参中是否含有@Param注解
private boolean hasParamAnnotation;
/**
* 参数名解析器的构造方法
* @param config 配置信息
* @param method 要被分析的方法
*/
public ParamNameResolver(Configuration config, Method method) {
// 获取参数类型列表
final Class<?>[] paramTypes = method.getParameterTypes();
// 准备存取所有参数的注解,是二维数组
final Annotation[][] paramAnnotations = method.getParameterAnnotations();
final SortedMap<Integer, String> map = new TreeMap<>();
int paramCount = paramAnnotations.length;
// 循环处理各个参数
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
if (isSpecialParameter(paramTypes[paramIndex])) {
// 跳过特别的参数
continue;
}
// 参数名称
String name = null;
for (Annotation annotation : paramAnnotations[paramIndex]) {
// 找出参数的注解
if (annotation instanceof Param) {
// 如果注解是Param
hasParamAnnotation = true;
// 那就以Param中值作为参数名
name = ((Param) annotation).value();
break;
}
}
if (name == null) {
// 否则,保留参数的原有名称
if (config.isUseActualParamName()) {
name = getActualParamName(method, paramIndex);
}
if (name == null) {
// 参数名称取不到,则按照参数index命名
name = String.valueOf(map.size());
}
}
map.put(paramIndex, name);
}
names = Collections.unmodifiableSortedMap(map);
}
debug跟踪后 names的结果如下:
2.ParamNameResolver的getNamedParams函数是在确定names属性后,给出方法参数名->参数值的映射
源码如下:
public Object getNamedParams(Object[] args) {
final int paramCount = names.size();
if (args == null || paramCount == 0) {
return null;
} else if (!hasParamAnnotation && paramCount == 1) {
return args[names.firstKey()];
} else {
final Map<String, Object> param = new ParamMap<>();
int i = 0;
for (Map.Entry<Integer, String> entry : names.entrySet()) {
// 首先按照类注释中提供的key,存入一遍 【参数的@Param名称 或者 参数排序:实参值】
// 注意,key和value交换了位置
param.put(entry.getValue(), args[entry.getKey()]);
// add generic param names (param1, param2, ...)
final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
// ensure not to overwrite parameter named with @Param
// 再按照param1, param2, ...的命名方式存入一遍
if (!names.containsValue(genericParamName)) {
param.put(genericParamName, args[entry.getKey()]);
}
i++;
}
return param;
}
}
假设对上边自己定义的接口调用
getUserInfo(1,18,"波多野结衣")
debug跟踪他返回的结果是: