博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
mybatis随笔四之MapperProxy
阅读量:6457 次
发布时间:2019-06-23

本文共 6053 字,大约阅读时间需要 20 分钟。

在上一篇文章我们已经得到了mapper的代理对象,接下来我们对demoMapper.getDemo(1)这种语句进行分析。 由于返回的mapper是个代理对象,因此会进入invoke方法,接下来我们来看看MapperProxy的invoke方法。
@Override  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {    if (Object.class.equals(method.getDeclaringClass())) {      try {        return method.invoke(this, args);      } catch (Throwable t) {        throw ExceptionUtil.unwrapThrowable(t);      }    }    final MapperMethod mapperMethod = cachedMapperMethod(method);    return mapperMethod.execute(sqlSession, args);  }
Object.class.equals(method.getDeclaringClass())的意思是如果定义方法的类是个具体类就使用具体类的实现,如果是接口则往下执行。
private MapperMethod cachedMapperMethod(Method method) {    MapperMethod mapperMethod = methodCache.get(method);    if (mapperMethod == null) {      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());      methodCache.put(method, mapperMethod);    }    return mapperMethod;  }
methodCache是个Map
对象,第一次取时为空会进入MapperMethod构造方法。
public MapperMethod(Class
mapperInterface, Method method, Configuration config) { this.command = new SqlCommand(config, mapperInterface, method); this.method = new MethodSignature(config, method); }
public SqlCommand(Configuration configuration, Class
mapperInterface, Method method) { String statementName = mapperInterface.getName() + "." + method.getName(); MappedStatement ms = null; if (configuration.hasStatement(statementName)) { ms = configuration.getMappedStatement(statementName); } else if (!mapperInterface.equals(method.getDeclaringClass())) { // issue #35 String parentStatementName = method.getDeclaringClass().getName() + "." + method.getName(); if (configuration.hasStatement(parentStatementName)) { ms = configuration.getMappedStatement(parentStatementName); } } if (ms == null) { if(method.getAnnotation(Flush.class) != null){ name = null; type = SqlCommandType.FLUSH; } else { throw new BindingException("Invalid bound statement (not found): " + statementName); } } else { name = ms.getId(); type = ms.getSqlCommandType(); if (type == SqlCommandType.UNKNOWN) { throw new BindingException("Unknown execution method for: " + name); } } }
这里主要做了这几件事,根据方法名以及接口名的组合从configuration中取得对应的MappedStatement,然后从中取出name和type。

MethodSignature构造方法如下
public MethodSignature(Configuration configuration, Method method) {      this.returnType = method.getReturnType();      this.returnsVoid = void.class.equals(this.returnType);      this.returnsMany = (configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray());      this.mapKey = getMapKey(method);      this.returnsMap = (this.mapKey != null);      this.hasNamedParameters = hasNamedParams(method);      this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);      this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);      this.params = Collections.unmodifiableSortedMap(getParams(method, this.hasNamedParameters));    }
这里主要是标记下入参中的RowBounds、ResultHandler类型参数,以及对返回值进行些标记。 MethodSignature与SqlCommand初始化后MapperMethod也就构造完成,然后methodCache将method与mapperMethod关系保留。 接下来就是屌用mapperMethod的execute方法来执行。
public Object execute(SqlSession sqlSession, Object[] args) {    Object result;    if (SqlCommandType.INSERT == command.getType()) {      Object param = method.convertArgsToSqlCommandParam(args);      result = rowCountResult(sqlSession.insert(command.getName(), param));    } else if (SqlCommandType.UPDATE == command.getType()) {      Object param = method.convertArgsToSqlCommandParam(args);      result = rowCountResult(sqlSession.update(command.getName(), param));    } else if (SqlCommandType.DELETE == command.getType()) {      Object param = method.convertArgsToSqlCommandParam(args);      result = rowCountResult(sqlSession.delete(command.getName(), param));    } else if (SqlCommandType.SELECT == command.getType()) {      if (method.returnsVoid() && method.hasResultHandler()) {        executeWithResultHandler(sqlSession, args);        result = null;      } else if (method.returnsMany()) {        result = executeForMany(sqlSession, args);      } else if (method.returnsMap()) {        result = executeForMap(sqlSession, args);      } else {        Object param = method.convertArgsToSqlCommandParam(args);        result = sqlSession.selectOne(command.getName(), param);      }    } else if (SqlCommandType.FLUSH == command.getType()) {        result = sqlSession.flushStatements();    } else {      throw new BindingException("Unknown execution method for: " + command.getName());    }    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {      throw new BindingException("Mapper method '" + command.getName()           + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");    }    return result;  }
我们的mapper方法定义如下,返回的不是集合也不为空,因此进入convertArgsToSqlCommandParam方法。 convertArgsToSqlCommandParam对入参进行转换,如果没有入参返回null如果一个入参对象则直接返回,多个入参则封装成个map对象返回。
public Demo getDemo(long id);
现在进入到sqlSession的selectOne方法,使用ibatis的同学应该相当熟悉。 在selectOne内部调用了selectList方法,然后返回集合对象的第一个元素,如果集合对象大于1个则抛错。
@Override  public 
List
selectList(String statement, Object parameter, RowBounds rowBounds) { try { MappedStatement ms = configuration.getMappedStatement(statement); return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER); } catch (Exception e) { throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }
rowBounds是用来分页的,暂时不管该对象,默认的初始值如下
public static final int NO_ROW_OFFSET = 0;public static final int NO_ROW_LIMIT = Integer.MAX_VALUE;
selectList也是根据statement从configuration中取得mappedStatement,然后交由executor来执行,sqlSessionFactory构建的时候默认使用的是simpleExecutor

到这里我们分析了mapper接口的方法最终是交到executor来执行。
 
 
 

转载地址:http://cqizo.baihongyu.com/

你可能感兴趣的文章
C#_delegate - 调用列表
查看>>
交换机二层接口access、trunk、hybird三种模式对VLAN的处理过程
查看>>
jQuery.extend 函数详解
查看>>
[转]Windows的批处理脚本
查看>>
lnmp高人笔记
查看>>
[转载] OpenCV2.4.3 CheatSheet学习(三)
查看>>
C#中跨窗体操作(2)--消息机制
查看>>
子程序框架
查看>>
多维数组元素的地址
查看>>
maven的错误记录
查看>>
数据库运维体系_SZMSD
查看>>
aspose 模板输出
查看>>
福大软工1816 · 第三次作业 - 结对项目1
查看>>
selenium多个窗口切换
查看>>
《单页面应用》所获知识点
查看>>
静态库 调试版本 和发布版本
查看>>
DB2 错误码解析
查看>>
读书笔记四
查看>>
JAVA中的finalize()方法
查看>>
慕课网学习手记--炫丽的倒计时效果Canvas绘图与动画基础
查看>>