1. 程式人生 > >MyBatis原始碼分析之抽象工廠模式和建造者模式的應用

MyBatis原始碼分析之抽象工廠模式和建造者模式的應用

抽象工廠模式的應用

MyBatis原始碼的註釋不多,不過SqlSession倒是給了兩行註釋:

/**
 * The primary Java interface for working with MyBatis.
 * Through this interface you can execute commands, get mappers and manage transactions.
 * @author Clinton Begin
 */
public interface SqlSession extends Closeable {}

第一行註釋告訴我們SqlSession是使用MyBatis的主要介面,SqlSession有一個預設的實現類DefaultSqlSession,另外一個實現類SqlSessionManager(通過實現介面SqlSessionFactory,增加了工廠的能力)在後面的博文中會有詳細的分析。

再看SqlSessionFactory只給了一行註釋:

/**
 * Creates an {@link SqlSession} out of a connection or a DataSource
 * @author Clinton Begin
 */
 public interface SqlSessionFactory {}

註釋告訴我們,介面SqlSessionFactory用於從資料來源或資料庫連線中建立SqlSession,SqlSessionFactory也有一個預設的實現類DefaultSqlSessionFactory,另外一個實現類SqlSessionManager,再次不做贅述。

下面看DefaultSqlSessionFacotry中實際產生SqlSession物件的兩個方法(從資料來源和資料庫連線中獲取):

// 從資料來源中開啟Session
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); // 實際返回的是DefaultSqlSession 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(); } } // 從資料庫連線中開啟Session private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) { try { boolean autoCommit; try { autoCommit = connection.getAutoCommit(); } catch (SQLException e) { // Failover to true, as most poor drivers // or databases won't support transactions autoCommit = true; } final Environment environment = configuration.getEnvironment(); final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); final Transaction tx = transactionFactory.newTransaction(connection); final Executor executor = configuration.newExecutor(tx, execType); // 實際返回的是DefaultSqlSession return new DefaultSqlSession(configuration, executor, autoCommit); } catch (Exception e) { throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e); } finally { ErrorContext.instance().reset(); } }

從上面的程式碼得知,實際由DefaultSqlSessionFactory生產DefaultSqlSession物件。

通過上面的分析,可以看出SqlSession和SqlSessionFactory這兩個介面,及DefaultSqlSession和DefaultSqlSessionFactory這兩個預設實現類,就是典型的抽象工廠模式的實現。

建造者模式的應用

上面講述了SqlSession的實現類的產生過程,那麼SqlSessionFactory是怎麼產生的呢?

SqlSessionFactory是由SqlSessionFactoryBuilder產生的,程式碼如下:

public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
}

DefaultSqlSessionFactory的構造器需要傳入MyBatis核心配置類Configuration的物件作為引數,而Configuration龐大且複雜,初始化比較麻煩,使用了專門的建造者XMLConfigBuilder進行構建。

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      // 建立建造者XMLConfigBuilder例項
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      // XMLConfigBuilder的parse()構建Configuration例項
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
 }

XMLConfigBuilder負責Configuration例項各個元件的建立和裝配,整個裝配的流程化過程如下:

private void parseConfiguration(XNode root) {
    try {
      //issue #117 read properties first
      // Configuration#
      propertiesElement(root.evalNode("properties"));
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      // read it after objectFactory and objectWrapperFactory issue #631
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
}

XMLConfigBuilder負責建立複雜物件Configuration,SqlSessionFactoryBuilder只不過是做了一層封裝去構建SqlSessionFactory例項,這是建造者模式的簡化構建過程。