Mybatis3.5.4源码分析-3- 获取mapper,反射调用查询

本文深入剖析Mybatis3.5.4中getMapper接口获取及动态代理过程。从DefaultSqlSession的getMapper方法开始,通过Configuration获取MapperProxyFactory,接着创建mapper接口的动态代理对象。MapperMethod的SqlCommand和MethodSignature封装关键信息,执行execute方法并调用selectOne,最终在SimpleExecutor的doQuery方法中完成数据库查询,涉及StatementHandler、ParameterHandler和ResultSetHandler的创建与插件逻辑。
摘要由CSDN通过智能技术生成
 BlogMapper mapper = session.getMapper(BlogMapper.class);

mybatis中,通过session.getMapper来获取mapper接口的实现类,同样的,ctrl+alt+B 进入这个方法的默认实现
org.apache.ibatis.session.defaults.DefaultSqlSession#getMapper 中:

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

它的实现是从全局配置类中获取mapper接口的实现:
org.apache.ibatis.session.Configuration#getMapper , 在前面的分析中,我们知道了knownMappers 保存的是mapper接口和MapperProxyFactory 之间的映射关系,因此这里先获取到了MapperProxyFactory这个工厂类,然后通过JDK动态代理创建了mapper接口的实现类:

  @SuppressWarnings("unchecked")
  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 {
   
      // 反射创建代理对象,是mapper接口的实现(代理类)
      return mapperProxyFactory.newInstance(sqlSession);
    } catch (Exception e) {
   
      throw new BindingException("Error getting mapper instance. Cause: " + e, e);
    }
  }

动态代理创建mapper对象的过程如下:

  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
   
    // 参数1: 类加载器
    // 参数2: 被代理类实现的接口
    // 参数3: 实现了InvocationHandler接口的一个代理类,后面执行代理类的方法时,会走到mapperProxy的invoke方法里面!
    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);
  }

总结一下getMapper所做的事情:
1、 通过getmapper 获取工厂类MapperProxyFactory
2、 通过 MapperProxyFactory创建了一个代理类对象
既然是动态代理,那么必然会有一个invoke方法,如下:

@Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   
    try {
   
      // 从Object类继承的toString  hashCode  equals getClass等方法无需走执行sql的流程
      if (Object.class.equals(method.getDeclaringClass())) {
   
        return method.invoke(this, args);
      } else {
   
        // 提升获取mapperMethod的效率,到mapperMathodInvoker(内部接口)的invoke
        // 普通方法会走到plainMethodInvoker的invoke
        return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
      }
    } catch (Throwable t) {
   
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }
private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
   
    try {
   
      // java8中的map方法,根据key获取值,如果值是null,则把后面Object的值
      // 赋给key,如果获取不到,就创建,
      // 虎丘的是mapperMethdoInvoker接口对象,只有一个invoke方法
      return methodCache.computeIfAbsent(method, m -> {
   
        if (m.isDefault()) {
   
          // 接口的默认方法(java8)只要实现接口,都会继承接口的默认方法,例如List.sort()
          try {
   
            if (privateLookupInMethod == null) {
   
              return new DefaultMethodInvoker(getMethodHandleJava8(method));
            } else {
   
              return new DefaultMethodInvoker(getMethodHandleJava9(method));
            }
          } catch (IllegalAccessException | InstantiationException | InvocationTargetException
              | NoSuchMethodException e) {
   
            throw new RuntimeException(e);
          }
        } else {
   
         // 普通方法返回PlainMethodInvoker
          return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
        }
      });
    } catch (RuntimeException re) 
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值