从源码看世界:Mybatis初始化过程(下)

看完sql生成过程,我们再来看看mapper接口的实例化。众所周知,接口是无法实例化的,那Mybatis到底实例出来的是什么东西呢?

 

mapper的实例化通过SqlSession获取的,因此我们先来看看SqlSession的创建过程:

  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      final Executor executor = configuration.newExecutor(tx, execType);
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

可以看到Executor也在这里实例化了,还记得Executor是真正发起数据库操作的执行器,并且Executor有多个实现类,这里到底使用的是哪个实现类呢

  public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
    executorType = executorType == null ? defaultExecutorType : executorType;
    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
    Executor executor;
    if (ExecutorType.BATCH == executorType) {
      executor = new BatchExecutor(this, transaction);
    } else if (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
    if (cacheEnabled) {
      executor = new CachingExecutor(executor);
    }
    executor = (Executor) interceptorChain.pluginAll(executor);
    return executor;
  }

发现Executor一共四个实现类:BatchExecutor、ReuseExecutor、SimpleExecutor、CachingExecutor,其用途看名字基本可以猜出来:

  • SimpleExecutor:常规执行器,每次执行都会创建一个statement,用完后关闭。
  • ReuseExecutor:可重用执行器,将key=sql,value=statement存入map中,操作map中的statement而不会重复创建statement。
  • BatchExecutor:批处理型执行器,doUpdate预处理存储过程或批处理操作,doQuery提交并执行过程。
  • CachingExecutor: 缓存执行器,用于包装以上三个执行器,缓存 statement的id、查询offset/limit、sql、参数和环境id,属于二级缓存(此二级非二级分布式缓存,它由事务缓存管理器提供,仍然存储于本地)。

另外,我们还留意到interceptorChain.pluginAll(executor);,看起来跟web的filter链十分相似,其实内部的确是一条责任链:

  public Object pluginAll(Object target) {
    for (Interceptor interceptor : interceptors) {
      target = interceptor.plugin(target);
    }
    return target;
  }

通过查看其调用链,我们发现不仅executor调用了:

up-6d1f9754310dd5c9d904ca20d609ee17fe0.png

这是Mybatis的一种扩展机制,通过拦截器添加自定义操作,需要实现各自的接口并实现到全局配置中。

注意: Inteceptor是使用JDK的动态代理来实现的,所以它只能对接口进行拦截

executor创建完成后,将其与Configuration一起传入DefaultSqlSession,至此SqlSession创建完成。接下来利用SqlSession.getMapper实例化mapper,实际上是通过mapperRegistry进行。还记得mapperRegistry一开始在解析mapper时创建了 Mapper代理工厂类MapperProxyFactory,这个工厂类同样是使用了JDK的动态代理来创建代理类MapperProxy:

  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);
  }

当调用mapper方法时,就会进入其实现了InvocationHandler的invoke方法,之后的流程在  从源码看世界:Mybatis一次数据库操作过程  已说明,这里不再叙述。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值