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

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

mapper的实例化经过SqlSession获取的,所以咱们先来看看SqlSession的建立过程:web

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有多个实现类,这里到底使用的是哪一个实现类呢sql

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调用了:session

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

注意:Inteceptor是使用JDK的动态代理来实现的,因此它只能对接口进行拦截分布式

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

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一次数据库操做过程已说明,这里再也不叙述。this

相关文章
相关标签/搜索