下面是一个简单的Mapper接口调用,首先同个session的getMapper方法获取Mapper的代理对象,然后通过代理对象去调用Mapper接口的方法

            EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
Employee employee = mapper.getEmpByIdAndName(1,"tom");
Employee getEmpByIdAndName(@Param("id") Integer id, @Param("name") String name, int age);

源码分析:

首先看MapperProxy类,关键是mapperMethod.execute(this.sqlSession, args);

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
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 = this.cachedMapperMethod(method);
return mapperMethod.execute(this.sqlSession, args);
}

MapperMethod类:execute方法中,在调用session操作之前,都会调用this.method.convertArgsToSqlCommandParam(args),最终还是调用ParamNameResolver类

    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;
}
}
public Object convertArgsToSqlCommandParam(Object[] args) {
return this.paramNameResolver.getNamedParams(args);
}
 
ParamNameResolver类, 参数会保存成这样的格式{id:1,name:Tom,2:30,param1:1,param2:Tom,param3:30}

public class ParamNameResolver {

  private static final String GENERIC_NAME_PREFIX = "param";
private final SortedMap<Integer, String> names;
private boolean hasParamAnnotation;
  // 构造器来初始化names,其值是{0=id, 1=name, 2=2}
public ParamNameResolver(Configuration config, Method method) {
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) {
if (!isSpecialParameter(paramTypes[paramIndex])) {
String name = null;
Annotation[] var9 = paramAnnotations[paramIndex];
int var10 = var9.length; for(int var11 = 0; var11 < var10; ++var11) {
Annotation annotation = var9[var11];
if (annotation instanceof Param) { // 如果使用了param注解的参数,例如@Param("id")
this.hasParamAnnotation = true;
name = ((Param)annotation).value(); // name = "id";
break;
}
} if (name == null) {
if (config.isUseActualParamName()) { // 如果配置文件中配置了useActualParamName=true
               //允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的项目必须采用 Java 8 编译,并且加上 -parameters 选项。(新增于 3.4.1)
name = this.getActualParamName(method, paramIndex); // name=参数名称(id)
} if (name == null) {
name = String.valueOf(map.size()); // name=当前map的索引 name=2
}
} map.put(paramIndex, name);
}
} this.names = Collections.unmodifiableSortedMap(map);
} private String getActualParamName(Method method, int paramIndex) {
return (String)ParamNameUtil.getParamNames(method).get(paramIndex);
} private static boolean isSpecialParameter(Class<?> clazz) {
return RowBounds.class.isAssignableFrom(clazz) || ResultHandler.class.isAssignableFrom(clazz);
} public String[] getNames() {
return (String[])this.names.values().toArray(new String[0]);
}
    
public Object getNamedParams(Object[] args) { // args【1,"Tom",30】
      // names:{0=id, 1=name, 2=2};构造器的时候就确定好了
int paramCount = this.names.size();
if (args != null && paramCount != 0) {
if (!this.hasParamAnnotation && paramCount == 1) { // 如果只有一个元素,并且没有Param注解;
return args[(Integer)this.names.firstKey()]; // 直接返回args[0]
} else { // 多个元素或者有Param标注
Map<String, Object> param = new ParamMap();
int i = 0; for(Iterator var5 = this.names.entrySet().iterator(); var5.hasNext(); ++i) {
Entry<Integer, String> entry = (Entry)var5.next();
            /
/names集合的value作为key; names集合的key又作为取值的参考args[0]

              //eg:{id=args[0]:1,name=args[1]:Tom,2=args[2]:30}

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

            //额外的将每一个参数也保存到map中,使用新的key:param1...paramN
            //效果:有Param注解可以#{指定的key},或者#{param1}

                    String genericParamName = "param" + String.valueOf(i + 1);
if (!this.names.containsValue(genericParamName)) {
param.put(genericParamName, args[(Integer)entry.getKey()]);
}
} return param;
}
} else {
return null;
}
}
}

【Mybatis】Mapper接口的参数处理过程的更多相关文章

  1. Mybatis Mapper接口是如何找到实现类的-源码分析

    KeyWords: Mybatis 原理,源码,Mybatis Mapper 接口实现类,代理模式,动态代理,Java动态代理,Proxy.newProxyInstance,Mapper 映射,Map ...

  2. 基于注解的Mybatis mapper 接口注意事项

    基于注解的Mybatis mapper 接口功能没有mapper xml配置文件丰富,并且动态sql语句的灵活性不能和xml配置相比. 这里仅仅说一下基于注解的动态sql注意事项: Mybatis提供 ...

  3. mybatis中mapper接口的参数设置几种方法

    方法一:忽略parameterType,加@param("xxx")注解 在mapper接口中加上@param("xxx")注解,则在配置文件中直接用即可 Li ...

  4. MyBatis Mapper 接口如何通过JDK动态代理来包装SqlSession 源码分析

    我们以往使用ibatis或者mybatis 都是以这种方式调用XML当中定义的CRUD标签来执行SQL 比如这样 <?xml version="1.0" encoding=& ...

  5. mybatis mapper接口开发dao层

    本文将探讨使用 mapper接口,以及 pojo 包装类进行 dao 层基本开发 mybatis dao 层开发只写 mapper 接口 其中需要 开发的接口实现一些开发规范 1. UserMappe ...

  6. mapper接口方法参数

    mapper接口中的方法只有一个参数,是不影响程序员开发的可以将参数指定为 pojo类型 或 map

  7. Mybatis mapper接口与xml文件路径分离

    为什么分离 对于Maven项目,IntelliJ IDEA默认是不处理src/main/java中的非java文件的,不专门在pom.xml中配置<resources>是会报错的,参考这里 ...

  8. myBatis mapper接口方法重载问题

    在mybatis框架中,写dao层的mapper接口时,是不可以进行方法的重载的,下面是截图证明:   当mapper接口中有方法的重载时,会出现异常,   这是mapper接口中定义的两个方法,进行 ...

  9. AOP之proceedingjoinpoint和joinpoint区别(获取各对象备忘)、动态代理机制及获取原理代理对象、获取Mybatis Mapper接口原始对象

    现在AOP的场景越来越多,所以我们有必要理解下和AOP相关的一些概念和机制. import org.aspectj.lang.reflect.SourceLocation; public interf ...

随机推荐

  1. 外网访问内网的FTP服务器

    转自 外网访问内网的FTP服务器 首先感谢作者给出的总结,原文是介绍Serv-U的,我针对FileZilla Server进行了稍微修改,仅看操作可直接跳到分割线后第3部分. 1. 背景简介最近研究如 ...

  2. CORS和jsonp实现跨域请求

    同源策略:所谓同源是指,域名,协议,端口相同,它是由Netscape提出的一个著名的安全策略,现在所有支持JavaScript 的浏览器都会使用这个策略.当浏览器同时打开两个tab页面(两个不同服务器 ...

  3. Android自定义权限与使用

    1. 如何自定义权限 Android允许我们使用permission标签,在Manifest文件中定义属于自己的权限,一个例子如下, <?xml version="1.0" ...

  4. CSS 背景色变化 结构化伪类的练习

    CSS3的nth-child() 选择器(兼容性不好),在做表格偶数行变色的时候,我通常在绑定的时候,做一个js判断,来加一个css,从而使表格偶数行和奇数行颜色不一样.这样的兼容性很好. 但是最近在 ...

  5. 一个伪静态与404重定向例子(房产网),.htaccess文件内容

    ErrorDocument 404 /404.phpRewriteEngine OnRewriteBase /RewriteRule ^(.*)\.(asp|aspx|asa|asax|dll|jsp ...

  6. 小D课堂 - 新版本微服务springcloud+Docker教程_4-04 高级篇幅之服务间调用之负载均衡策略调整实战

    笔记 4.高级篇幅之服务间调用之负载均衡策略调整实战     简介:实战调整默认负载均衡策略实战 自定义负载均衡策略:http://cloud.spring.io/spring-cloud-stati ...

  7. iOS启动图launchImage设置后在启动时无法显示

    iOS设置启动图: 会发现运行APP不显示设置好的启动图 解决方法: 卸载之前运行的APP,检查以下配置,将LaunchScreen删除即可. 原因: launchImage 是在没有LaunchSc ...

  8. unmix和conditional average:消混叠和条件均值

    unmix 该程序用来消除“像素混叠”.所谓像素混叠,是值在自然场景的图像中,边缘线成像到cmos的像素上时,某些像素会刚好跨在该边缘线上. 这样的像素特点就是,其R.G.B三色像素梯度值不一致.比如 ...

  9. 【VS开发】这就是COM组件

    [实例]这就是COM组件 时间 2012-02-21 10:49:15  CSDN博客 原文  http://blog.csdn.net/btwsmile/article/details/727849 ...

  10. [转帖]图解SSL/TLS协议

    图解SSL/TLS协议   作者: 阮一峰 日期: 2014年9月20日 感谢 腾讯课堂NEXT学院 赞助本站,腾讯官方的前端课程 免费试学. http://www.ruanyifeng.com/bl ...