從源碼看世界: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

相關文章
相關標籤/搜索