MyBatis 接口参数与 XML SQL 参数实现动态拼接详解
共分为五个步骤:
- 接口参数解析
- 根据参数名获取参数值
- Collection、List、Map 类型参数再次封装
- 接口参数与动态上下文对象绑定
- 参数与 SQL 拼接
- 补充
接口参数解析
代码流程如下:
详情代码段:
ParamNameResolver.class
/**
* @Param config MyBatis 的全局配置对象
*
* @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;
// get names from @Param annotations
for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {
...
String name = null;
// 如果参数前使用了 @Param 注解,则获取到参数名
for (Annotation annotation : paramAnnotations[paramIndex]) {
if (annotation instanceof Param) {
hasParamAnnotation = true;
name = ((Param) annotation).value();
break;
}
}
// 如果参数未使用 @Param 注解
if (name == null) {
// 请留意此处....
// 则使用默认的参数名 useActualParamName 属性默认为 true ,则参数名的格式为:arg0,arg1...
if (config.isUseActualParamName()) {
name = getActualParamName(method, paramIndex);
}
if (name == null) {
// 如果 useActualParamName 被配置为 false ,则参数名为索引名,如:"0", "1", ...
name = String.valueOf(map.size());
}
}
map.put(paramIndex, name);
}
names = Collections.unmodifiableSortedMap(map);
}
// 最终 names 的内容如下:
// Map 类型:paramIndex --》 paramName
分析 ParamNameResolver 的构造器方法中可以得出以下结论:
- 当我们使用 @Param 注解时,参数名为注解中设置的值
- 未使用注解时,未设置全局的 useActualParamName 配置时,useActualParamName 默认配置为 true,则参数名会被设置为:arg0,arg1… 格式
- 未使用注解时,设置全局的 useActualParamName = false 后,参数名会被设置为:“0”, “1”, … 格式
根据参数名获取参数值:
下图为获取具体参数值调用流程:
可以看到,分支2 的调用,最终也是调用的 ParamNameResolver 类中的方法进行参数的获取:
ParamNameResolver.class
/**
* @Param args 接口中传入的参数值,数组形式
*
* @return 单个参数,且没有使用 @Param 注解时,直接返回参数值;多个参数时,返回:参数索引--》参数值 类型的 Map
*/
public Object getNamedParams