Mybatis源码分析--Mapper接口的代理生成原理

下面是mapper接口代理的生成逻辑
进入源码


进入getMapper看看


调用configuration的getMapper()
那么mapperRegistry是什么呢?我们看下

MapperRegistry含有两个属性。configuratio和Map。Map的key是class,value是MapperProxyFactory。那么,这个MapperProxyFactory又是什么呢?
看到该类的属性,一个Class对象,即是我们定义的Mapper接口类。一个Map来表示方法缓存。看到2个newInstance方法,立马想到应该是创建代理了。点开这两个方法
根据给定的sqlsession和接口和方法缓存创建一个mapperProxy。该类实现了InvocationHandler。那么 我们进入到其invoke()方法
该方法首先判断方法是否的Object类的方法,如果是,则不执行代理,直接进行。如果不是,执行cachedMapperMethod 方法 并调用返回对象 MapperMethod 的execute 方法。我们看看cachedMapperMethod方法,应该和缓存有关.

 private MapperMethod cachedMapperMethod(Method method) {
    return methodCache.computeIfAbsent(method, k -> new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
  }
复制代码

看下 MapperMethod的构造方法,构造了SqlCommand和MethodSignature两个对象。它们都是MapperMethod的静态内部类。
SqlCommand类有2个属性,它们是怎么得到的呢?从resolveMappedStatement()方法的返回值得到的。我们进入该方法看下

public static class SqlCommand {
    private final String name;//表示sql语句的名称
    private final SqlCommandType type;//表示sql语句的类型

    public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
      final String methodName = method.getName();
      final Class<?> declaringClass = method.getDeclaringClass();
      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 {
        name = ms.getId();
        type = ms.getSqlCommandType();
        if (type == SqlCommandType.UNKNOWN) {
          throw new BindingException("Unknown execution method for: " + name);
        }
      }
    }
    
     private MappedStatement resolveMappedStatement(Class<?> mapperInterface, String methodName,
        Class<?> declaringClass, Configuration configuration) {
        //获取id
      String statementId = mapperInterface.getName() + "." + methodName;
      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;
    }
复制代码

SqlCommandType是枚举。
拿到mapperMethod,进入excute();
此时返回代理对象

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

my.oschina.net/heweipo/blo…

通过上面的代码,我们拿到了代理。那么,如何用这个代理呢?利用这个代理会代理到什么方法上呢?
那么既然有了 MapperProxy 对象,只要在这个对象的invoke方法里调用执行 SQL 语句就达到目的了,因此也就不需要接口实现类了

转载于:https://juejin.im/post/5b514c56f265da0f4d0d748e

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值