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例項,這是建造者模式的簡化構建過程。