Mybatis框架源码解读

3 篇文章 0 订阅
1 篇文章 0 订阅

Configuration:存储数据源,事务配置等信息
调用addMapper方法的时候它主要是调用的mapperRegistry的addMapper方法,
mapperRegistry会new一个MapperProxyFactory对象(构造函数的入参是我们的Mapper接口)
然后以Mapper接口的全限定名为key,MapperProxyFactory对象为值存放在Configuration内部的一个map对象中(knownMappers)
接下来就是调用MapperAnnotationBuilder的parse方法解析对应的xml文件或者是使用了注解的Mapper接口

public void parse() {
    String resource = type.toString();
    if (!configuration.isResourceLoaded(resource)) {
      //判断是否有xml文件,如果有的话,使用对应的xml解析器进行解析
      loadXmlResource();
      configuration.addLoadedResource(resource);
      //设置命名空间
      assistant.setCurrentNamespace(type.getName());
      //对CacheNamespace注解进行解析
      parseCache();
     //对CacheNamespaceRef注解进行解析
      parseCacheRef();
     //接下来是重点,对Mapper接口中的方法进行解析
      Method[] methods = type.getMethods();
      for (Method method : methods) {
        try {
          // issue #237
          if (!method.isBridge()) {
              //主要的解析方法,将解析出来的结果加到MappedStatement(assiant的属性)中             
              //生成MappedStatement的id值,解析对应的方法(增删改查),ResultMap,ParameterType,以及主键自增相关
              parseStatement(method);
          }
        } catch (IncompleteElementException e) {
           //解析失败的时候会先放在Configuration中一个LinkedList中(名字incompleteMethods)
          configuration.addIncompleteMethod(new MethodResolver(this, method));
        }
      }
    }
   //对刚才解析失败的方法再进行一次解析
    parsePendingMethods();
  }

当获取接口对象的时候是DefultSqlSession的getMapper方法,其实主要是通过Configuration调用MapperRegistry的getMapper方法,如下:
 

public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    //knowsMapper中通过接口的全限定名找到对应的MapperProxyFactory实体类
    final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
    if (mapperProxyFactory == null) {
      throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    }
    try {
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

下面是MapperProxyFactory的newInstance方法(可以看到主要就是使用了JDK动态代理帮我们生成了对应接口类的代理对象)

  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }

  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

那我们就知道了,调用对应的方法实质上就是调用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 (method.isDefault()) {
        if (privateLookupInMethod == null) {
          return invokeDefaultMethodJava8(proxy, method, args);
        } else {
          return invokeDefaultMethodJava9(proxy, method, args);
        }
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
   //缓存接口方法
    final MapperMethod mapperMethod = cachedMapperMethod(method);
   //最终的调用逻辑
    return mapperMethod.execute(sqlSession, args);
  }

 //MapperMethod的execute方法
 public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case INSERT: {
        Object param = method.convertArgsToSqlCommandParam(args);
        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()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
          if (method.returnsOptional()
              && (result == null || !method.getReturnType().equals(result.getClass()))) {
            result = Optional.ofNullable(result);
          }
        }
        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;
  }

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

上士闻道,勤而行之

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值