文章目录
准备工作
public interface UserDao {
User getUserOne(Integer id, User user, @Param("nameParam") String name, List<String> idList);
}
UserDao userDao = sqlSession.getMapper(UserDao.class);
User user = userDao.getUserOne(1,new User(1,"zhangsan"),"李四");
源码
1)实现InvocationHandler,动态代理
public class MapperProxy<T> implements InvocationHandler, Serializable {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
//objet中toStrong、hashCode类似方法,直接反射即可
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
//接口中的默认方法,这里暂时不研究
if (method.isDefault()) {
return this.invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
//获取MapperMethod
MapperMethod mapperMethod = this.cachedMapperMethod(method);
//执行sql语句
return mapperMethod.execute(this.sqlSession, args);
}
}
1、MapperMethod类内部类SqlCommand command。封装方法全限定名,以及sql标签枚举类型 insert,update,delete,select
2、MapperMethod类内部类MethodSignature method。封装方法的返回值和参数信息
2)mapperMethod.execute(this.sqlSession, args) 执行sql语句
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
Object param;
//根据枚举类型进入增删改查
switch(this.command.getType()) {
case INSERT:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
break;
case UPDATE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
break;
case DELETE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
break;
case SELECT:
//根据返回值的不同进入不同的方法
if (this.method.returnsVoid() && this.method.hasResultHandler()) {
this.executeWithResultHandler(sqlSession, args);
result = null;
} else if (this.method.returnsMany()) {
result = this.executeForMany(sqlSession, args);
} else if (this.method.returnsMap()) {
result = this.executeForMap(sqlSession, args);
} else if (this.method.returnsCursor()) {
result = this.executeForCursor(sqlSession, args);
} else {
param = this.method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(this.command.getName(), param);
if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + this.command.getName());
}
if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
} else {
return result;
}
}
3)param = this.method.convertArgsToSqlCommandParam(args) 获取参数
//内部类
public static class MethodSignature {
private final ParamNameResolver paramNameResolver;
...
public Object convertArgsToSqlCommandParam(Object[] args) {
//方法调用前ParamNameResolver创建对象,看构造函数
return this.paramNameResolver.getNamedParams(args);
}
...
}
获取name值,相当于key,后续会用到
public class ParamNameResolver {
private static final String GENERIC_NAME_PREFIX = "param";
private final SortedMap<Integer, String> names;
private boolean hasParamAnnotation;
public ParamNameResolver(Configuration config, Method method) {
//获取参数所有的Class类型
Class<?>[] paramTypes = method.getParameterTypes();
//获取每个参数的注解-每个参数可能有多个注解,故二维数组
Annotation[][] paramAnnotations = method.getParameterAnnotations();
SortedMap<Integer, String> map = new TreeMap();
int paramCount = paramAnnotations.length;
for(int paramIndex = 0; paramIndex < paramCount; ++paramIndex) {
// 检测当前的参数类型是否为 RowBounds 或 ResultHandler(是否特殊参数)
if (!isSpecialParameter(paramTypes[paramIndex])) {
String name = null;
Annotation[] var9 = paramAnnotations[paramIndex];
int var10 = var9.length;
//多个注解,只获取@param注解中的value值作为name
for(int var11 = 0; var11 < var10; ++var11) {
Annotation annotation = var9[var11];
if (annotation instanceof Param) {
this.hasParamAnnotation = true;
name = ((Param)annotation).value();
break;
}
}
if (name == null) {
//useActualParamName 配置项开启,name则为方法上参数名字
if (config.isUseActualParamName()) {
name = this.getActualParamName(method, paramIndex);
}
//如果没有注解,上面配置项没开启,name则为从0开始的数字字符串
if (name == null) {
name = String.valueOf(map.size());
}
}
map.put(paramIndex, name);
}
}
this.names = Collections.unmodifiableSortedMap(map);
}
}
mybatis配置选项useActualParamName 允许使用方法签名中的名称作为参数名称,但必须采用java8编译,并且加上-parameters选项
不满足以上条件,则会变成arg0、arg1…
private final SortedMap<Integer, String> names; 两种方式结果
4)核心代码
public Object getNamedParams(Object[] args) {
int paramCount = this.names.size();
if (args != null && paramCount != 0) {
//如果没@Param注解,且参数只有一个
if (!this.hasParamAnnotation && paramCount == 1) {
return args[(Integer)this.names.firstKey()];
} else {
Map<String, Object> param = new ParamMap();
int i = 0;
//遍历上面的map,将names value及arg0或者id作为key,通过names key作为索引获取arg[key]参数
for(Iterator var5 = this.names.entrySet().iterator(); var5.hasNext(); ++i) {
Entry<Integer, String> entry = (Entry)var5.next();
param.put((String)entry.getValue(), args[(Integer)entry.getKey()]);
//再添加一组 key = param1 value = 参数组的数组
String genericParamName = "param" + String.valueOf(i + 1);
if (!this.names.containsValue(genericParamName)) {
param.put(genericParamName, args[(Integer)entry.getKey()]);
}
}
return param;
}
} else {
return null;
}
}
- 如果参数没有@Param注解,且参数只有一个,直接通过Object[] args的arg[0]获取参数,此时参数名称无论写什么都可以
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/148671.html