Mybatis學習系列(七):Mapper執行

第六篇文章我們拿到了Mapper的一個代理對象,我們知道代理對象的執行其實是交給了InvocationHandler來處理的,也就是我們的MapperProxy對象。我們看一下invoke方法:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    //我們根據當前的方法在緩存中獲取MapperMethod 
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    //執行相應的方法
    return mapperMethod.execute(sqlSession, args);
  }

1.獲取MapperMethod 

private MapperMethod cachedMapperMethod(Method method) {
    //在緩存中獲取
    MapperMethod mapperMethod = methodCache.get(method);
    if (mapperMethod == null) {
      //如果沒有生成mapperMethod 
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      //加入當前緩存
      methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }

public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
    //初始化SqlCommand對象
    this.command = new SqlCommand(config, mapperInterface, method);
    //初始化MethodSignature對象
    this.method = new MethodSignature(config, mapperInterface, method);
  }

1.1初始化SqlCommand對象

public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
      //獲取當前方法名稱
      final String methodName = method.getName();
      //獲取當前方法 所屬的類
      final Class<?> declaringClass = method.getDeclaringClass();
      //這裏獲取MappedStatement 也就是我們解析mapper時生成的
      MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
          configuration);
      if (ms == null) {
        if (method.getAnnotation(Flush.class) != null) {
          name = null;
          type = SqlCommandType.FLUSH;
        } else {
          throw new BindingException("Invalid bound statement (not found): "
              + mapperInterface.getName() + "." + methodName);
        }
      } else {
        //這裏獲取MappedStatement 的ID
        name = ms.getId();
        //當前SQL的類型(增刪改查)
        type = ms.getSqlCommandType();
        if (type == SqlCommandType.UNKNOWN) {
          throw new BindingException("Unknown execution method for: " + name);
        }
      }
    }

1.1.1獲取MappedStatement 

private MappedStatement resolveMappedStatement(Class<?> mapperInterface, String methodName,
        Class<?> declaringClass, Configuration configuration) {
      //組裝ID 其實就是 之前設定的namespace.定義的ID(方法名稱)
      String statementId = mapperInterface.getName() + "." + methodName;
      //根據ID在緩存中獲取到了 直接返回
      if (configuration.hasStatement(statementId)) {
        return configuration.getMappedStatement(statementId);
      } else if (mapperInterface.equals(declaringClass)) {
        return null;
      }
      //如果當前方法不在當前接口中  往父類接口找
      for (Class<?> superInterface : mapperInterface.getInterfaces()) {
        if (declaringClass.isAssignableFrom(superInterface)) {
          MappedStatement ms = resolveMappedStatement(superInterface, methodName,
              declaringClass, configuration);
          if (ms != null) {
            return ms;
          }
        }
      }
      return null;
    }
  }

1.2初始化MethodSignature對象

public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
      //獲取當前方法的返回類型
      Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
      if (resolvedReturnType instanceof Class<?>) {
        this.returnType = (Class<?>) resolvedReturnType;
      } else if (resolvedReturnType instanceof ParameterizedType) {
        //泛型
        this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
      } else {
        this.returnType = method.getReturnType();
      }
      //是不是沒有返回值  void類型
      this.returnsVoid = void.class.equals(this.returnType);
      //返回的類型  是不是集合或者數組
      this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
      this.returnsCursor = Cursor.class.equals(this.returnType);
      //返回的map類型
      this.mapKey = getMapKey(method);
      this.returnsMap = this.mapKey != null;
      this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
      this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
      this.paramNameResolver = new ParamNameResolver(configuration, method);
    }

2.執行相應的方法

public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    //判斷當前sql的類型(增刪改查)
    switch (command.getType()) {
      case INSERT: {
      //解析入參
      Object param = method.convertArgsToSqlCommandParam(args);
        //調用sqlSession的insert方法
        //返回執行的行數
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
        //方法沒有返回值
        if (method.returnsVoid() && method.hasResultHandler()) {
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          //返回的是集合或者數組
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          //返回的是map
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          //返回的是單一對象
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        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;
  }

這裏可以最終調用的是sqlsession的方法,下一篇我們將詳細介紹每一個方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章