MyBatis @Param注解的实现

网友投稿 339 2022-08-16


MyBatis @Param注解的实现

先说结论:

当输入参数只有一个且没有使用@Param注解时,MyBatis会直接传递这个参数;当输入参数多于一个,或者使用了@Param注解时,MyBatis会将参数封装在Map中传递,这时的Map的key分为以下几种可能:

Map中会有param1, param2这样的key,其顺序对应输入参数的顺序。无论是否有@Param注解。对于@Param注解的参数,Map中会保存注解中给定的名字作为key对于没有用@Param注解的参数,Map中会用1、2、3 ..这样的数字作为key,按顺序保存输入参数。

下面来看一下源码。

首先,判断一个方法中是否有用@Param注解的参数:

private boolean hasNamedParams(Method method) {

final Object[][] paramAnnos = method.getParameterAnnotations();

for (Object[] paramAnno : paramAnnos) {

for (Object aParamAnno : paramAnno) {

if (aParamAnno instanceof Param) {

return true;

}

}

}

return false;

}

如果有用@Param注解的参数,取出注解中给出的参数名:

private String getParamNameFromAnnotation(Method method, int i, String paramName) {

final Object[] paramAnnos = method.getParameterAnnotations()[i]; // 获取第i个参数的注解

for (Object paramAnno : paramAnnos) {

if (paramAnno instanceof Param) {

paramName = ((Param) paramAnno).value();

break;

}

}

return paramName;

}

注意方法的输入参数,method表示是哪个方法上,i 表示第几个参数,  paramName是传进来的参数名,如果该参数没有用@Param注解,则返回传进来的paramName。

下面这个方法返回一个TreeMap(有序),其key表示参数的顺序,比如key=0代表第0个参数;value表示参数的名字,如果有用@Param注解标注,则为标注的参数名,否则和key相等,即用参数的序号作为参数的名字。

private SortedMap getParams(Method method, boolean hasNamedParameters) {

final SortedMap params = new TreeMap();

final Class>[] argTypes = method.getParameterTypes();

for (int i = 0; i < argTypes.length; i++) {

if (!RowBounds.class.isAssignableFrom(argTypes[i]) && !ResultHandler.class.isAssignableFrom(argTypes[i])) {

String paramName = String.valueOf(params.size()); // 参数名,默认为参数的序号

if (hasNamedParameters) { //如果有使用@Param注解,则获取注解标注的参数名

paramName = getParamNameFromAnnotation(method, i, paramName); // 这里paramName作为参数传进来,表示默认值

}

params.put(i, paramName);

}

}

return params;

}

其中hasNamedParameters只是从整个方法的维度,给出该方法是否有使用@Param注解的参数;即使其值为true,具体到某一个参数上面,可能没有使用@Param注解,因此调用getParamNameFromAnnotation传入的paramName就作为默认值返回,即参数的序号。

最后将调用方法的参数转换为MyBatis内部使用的参数:

public Object convertArgsToSqlCommandParam(Object[] args) {

final int paramCount = params.size();

if (args == null || paramCount == 0) {

return null;

} else if (!hasNamedParameters && paramCount == 1) {

return args[params.keySet().iterator().next().intValue()];

} else {

final Map param = new ParamMap();

int i = 0;

for (Map.Entry entry : params.entrySet()) {

param.put(entry.getValue(), args[entry.getKey().intValue()]);

// issue #71, add param names as param1, param2...but ensure backward compatibility

final String genericParamName = "param" + String.valueOf(i + 1);

if (!param.containsKey(genericParamName)) {

param.put(genericParamName, args[entry.getKey()]);

}

i++;

}

return param;

}

}

其中args为Dao方法的输入参数,这里已经转换成了数组,其实就是动态代理的invoke方法传入的参数。

该方法首先对输入参数进行计数,使用的params就是前面介绍的getParams方法的返回值。

if (!hasNamedParameters && paramCount == 1)

上面的条件判断,即方法没有使用@Param注解,且只有一个参数,这时返回

args[params.keySet().iterator().next().intValue()]

即直接将其作为Object返回。

如果上面的条件不满足的话,首先新建一个Map作为返回值:

final Map param = new ParamMap();

然后,设置map的key和value:

param.put(entry.getValue(), args[entry.getKey().intValue()]);

然后为了兼容性,做了如下操作

final String genericParamName = "param" + String.valueOf(i + 1);

if (!param.containsKey(genericParamName)) {

param.put(genericParamName, args[entry.getKey()]);

}

即设置param1、param2这样的key。

到此为止,需要的参数对象Object就构建完成,其中封装了Dao传入的多个参数,并根据参数是否有@Param注解,影响了参数对象的类型(是否是map)。

参数封装完成之后,下一步将其传递给SqlSession。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:浅谈Mybatis获取参数值的方式
下一篇:Jenkins初级使用过程中的异常处理
相关文章

 发表评论

暂时没有评论,来抢沙发吧~