MyBatis源码分析之策略模式和模板方法模式的应用

策略模式的应用

MyBatis配置文件mybatis-config.xml中的节点settings中有一项配置如下:

"defaultExecutorType" value="SIMPLE" />

配置的是MyBatis在运行过程中默认的执行器Executor,此项配置的默认值就是SIMPLE,指向就是接口Executor的实现类SimpleExecutor。

通过查看源码可以看得到接口Executor的继承关系如下:
MyBatis源码分析之策略模式和模板方法模式的应用_第1张图片

这些实现类为接口Executor的策略簇,实现了不同的执行器策略:

SimpleExecutor:普通的执行器
BatchExecutor:批处理执行器
ReuseExecutor:预处理语句重用执行器

MyBatis核心类Configuration类似于策略模式中的Context,区别于Context就是:Context维系是的传入的策略对象;Configuration是根据传入的策略对象类型,生产相应的策略对象,代码如下:

// 配置文件中setting属性为defaultExecutorType的对应Configuration属性
protected ExecutorType defaultExecutorType = ExecutorType.SIMPLE;
// 根据默认的执行器类型,生成相应的执行器对象
public Executor newExecutor(Transaction transaction) {
    return newExecutor(transaction, defaultExecutorType);
}
// 可指定执行器类型,生成相应的执行器对象
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;
}

执行器对象的使用者是接口的SqlSessionFactory的默认实现类DefaultSqlSessionFactory,用于生成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);
      // 调用Configuration的newExecutor(Transaction transaction,ExecutorType execType)生成执行器对象
      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有抽象接口BaseExecutor,其中以do开头的方法都符合模板方法设计模式,简单的分析可以看下面的代码分析:

// 查询
@Override
public  List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
    BoundSql boundSql = ms.getBoundSql(parameter);
    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
    // 调用query方法
    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
 }

 @SuppressWarnings("unchecked")
 @Override
 public  List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
    if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    if (queryStack == 0 && ms.isFlushCacheRequired()) {
      clearLocalCache();
    }
    List list;
    try {
      queryStack++;
      list = resultHandler == null ? (List) localCache.getObject(key) : null;
      if (list != null) {
        handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
      } else {
        list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
      }
    } finally {
      queryStack--;
    }
    if (queryStack == 0) {
      for (DeferredLoad deferredLoad : deferredLoads) {
        deferredLoad.load();
      }
      // issue #601
      deferredLoads.clear();
      if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
        // issue #482
        clearLocalCache();
      }
    }
    return list;
}

private  List queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
    List list;
    localCache.putObject(key, EXECUTION_PLACEHOLDER);
    try {
      list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
    } finally {
      localCache.removeObject(key);
    }
    localCache.putObject(key, list);
    if (ms.getStatementType() == StatementType.CALLABLE) {
      localOutputParameterCache.putObject(key, parameter);
    }
    return list;
 }

// 由上面的方法调用,子类实现此方法
protected abstract  List doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
      throws SQLException;

你可能感兴趣的:(设计模式,MyBatis)