参数对象的构建与获取
// MybatisMapperProxy的cachedMapperMethod方法中,如果methodCache没有methodName的话,会new
/* 最终会走到这个构造函数
该构造函数有一个Map类型的变量names,它的key是方法参数的下标,如果参数有@Param注释,value是@Param注解值,否则,是参数的名字
例如(@Param("id") int id1,int id2),那么names的值为0->id,1->id2
*/
ParamNameResolver->ParamNameResolver():
// 方法的参数类型
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++) {
String name = null;
for (Annotation annotation : paramAnnotations[paramIndex]) {
// 遍历参数注解,如果有@Param注解的话,name是注解值
if (annotation instanceof Param) {
// hasParamAnnotation,只要有一个参数带@Param,就为true
hasParamAnnotation = true;
name = ((Param) annotation).value();
break;
}
}
// 没有@Param注解,就取参数名称
if (name == null) {
name = getActualParamName(method, paramIndex);
}
map.put(paramIndex, name);
}
names = Collections.unmodifiableSortedMap(map);
ParamNameResolver->getNamedParams():
final int paramCount = names.size();
if (args == null || paramCount == 0) {
return null;
// 如果只有一个参数并且不带@Param标签的话,返回该参数
} else if (!hasParamAnnotation && paramCount == 1) {
return args[names.firstKey()];
} else {
// 否则返回Map类型,它的key是names里的value,值是对应参数值
......
}
总结
-
如果只有一个参数,并且不带@Param注解的话,返回的是调用该方法时所传对象值,否则返回的都是map类型
-
后面的取值中,如果返回的是参数对象值
- 如果是非预编译符
$类型(Integer x→${name}或Tree tree→${tree.id}),会利用MetaObject.getValue()最终调用Integer.getName()或Tree.getTree()方法 - 如果是预编译符
#类型(Integer x→#{name}),走的是最终拼接SQL探究里的MybatisDefaultParameterHandler->setParameters()同段逻辑
- 如果是非预编译符
-
如果返回的是map类型,不论是否预编译,调用map.get("name")方法获取参数值
| 参数情况 | names | 参数值 | sql语句 | 获取过程 |
|---|---|---|---|---|
| (Tree tree) | 0->tree | tree对象 | ${id} | Tree.getId() |
| (Tree tree) | 0->tree | tree对象 | #{id} | Tree.getId() |
| (Integer id) | 0->id | id值 | ${id} | Integer.getId() |
| (Integer id) | 0->id | id值 | #{id} | id值 |
| (@Param("tree") Tree tree) | 0->tree | tree->tree对象 | #/$ {tree.id} | map.get("tree")、tree.getId() |
| (@Param("origin") Integer id) | 0->origin | origin->id值 | #/$ {origin} | map.get("origin") |
| (Integer id1,Integer id2) | 0->id1,1->id2 | id1->id1值,id2->id2值 | #/$ {id1} | map.get("id1") |
| (@Param("origin")Integer id1,@Param("now")Integer id2) | 0->origin,1->now | origin->id1值,now->id2值 | #/$ {now} | map.get("now") |