MyBatis源码跟踪 - 获取mapper

接上文:获取线程不安全的SqlSession 上文已经获取到了SqlSession,那么下一步将通获取mapper了:

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

继续跟踪这个过程:

上文中得到的SqlSession的实现是DefaultSqlSession,那么看看它的getMapper方法:

  @Override
  public <T> T getMapper(Class<T> type) {
    return configuration.<T>getMapper(type, this);
  }

哦豁,还是configuration干的,OK,继续源码:

    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    return mapperRegistry.getMapper(type, sqlSession);
  }

嗯,交给了mapperRegistry(mapper注册器):

// 在初始化的时候就看到过,MapperRegistry维护了一个已知mapper的映射表,以类型做key,值是类型对应的代理工厂,通过addMapper等方法注册时加入到该映射表
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
// 获取Mapper
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
    // 首先拿到代理工厂,然后使用代理工厂产生一个实例返回
    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);
    }
  }

看来有必要跟一跟代理工厂了,怎么产生的这个实例:

// 又见动态代理
@SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }
  // 先调的这个,这个调上面的实现,不过核心在于new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }

又见动态代理,既然是jdk动态代理,那么核心就在于MapperProxy了,他们构造方法只是设置了几个属性,那么按jdk动态代理实现规范,必然是实现 了InvocationHandler,那么看看他的invoke方法(虽还没执行到这儿,先看看干了啥):

@Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // 定义该方法的类如果是Object就执行并返回
    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);
  }

纳尼?MapperMethod 是什么 东东? 我也没看懂,那就看看这个cachedMapperMethod方法吧:

// 属性: methodCache = new ConcurrentHashMap<Method, MapperMethod>();
private MapperMethod cachedMapperMethod(Method method) {
    MapperMethod mapperMethod = methodCache.get(method);
    if (mapperMethod == null) {
      // 这是关键,new一个MapperMethod,传入接口、方法、配置
      mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
      methodCache.put(method, mapperMethod);
    }
    return mapperMethod;
  }

哦,有点明白了,如果不是Object,不执行invoke,那么就拿到MapperMethod对象(新建或缓前面建了放在缓存里的),然后调用execute执行,再跟一跟这个execute方法?哦豁,有点长:

 // 比较明显,按SQL类型执行命令
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);
        }
        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;
  }

这个看上去应该能猜到,命令模式,按SQL的类型执行不同的命令,具体的SQL解析拼装先不管,需要专门讨论,具体执行命令的方法也不讨论,整体大根能看出来了,如何获取的Mapper;

这里面MapperMethod 是关键,而这个关键有两个属性,类型是它自己的两个内部类:

   // 顾名思义,分别是SQL命令对象和方法签名对象
  private final SqlCommand command;
  private final MethodSignature method;

看看他们是什么,先找构造方法:

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

具体这俩对象:

  • sqlCommand只有俩属性名称和类型,并且提供了getter方法:String name/SqlCommandType type
  • MethodSignature ,大概是描述一个方法的东西,先占坑后补,继续流程;

转载于:https://my.oschina.net/u/2407208/blog/897754

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值