在上一篇中,我們對ShardingGroupExecuteCallback和SQLExecuteTemplate做了介紹。從設計上講,前者充當ShardingExecuteEngine的回調入口,而後者則是一個模板類,完成對ShardingExecuteEngine的一層封裝並提供了對外的統一入口。這些類都位於底層的sharding-core-execute工程中。從今天開始,我們將進入到sharding-jdbc-core工程,來看看上層設計中的幾個核心類。
根據《ShardingSphere源碼解析之執行引擎(一)》中的整體結構圖,我們可以看到SQLExecuteTemplate的直接使用者是AbstractStatementExecutor類,今天我們就從這個類開始展開討論。該類的變量比較多,我們先來看一下:
private final DatabaseType databaseType;
private final int resultSetType;
private final int resultSetConcurrency;
private final int resultSetHoldability;
private final ShardingConnection connection;
private final SQLExecutePrepareTemplate sqlExecutePrepareTemplate;
private final SQLExecuteTemplate sqlExecuteTemplate;
private final Collection<Connection> connections = new LinkedList<>();
private SQLStatementContext sqlStatementContext;
private final List<List<Object>> parameterSets = new LinkedList<>();
private final List<Statement> statements = new LinkedList<>();
private final List<ResultSet> resultSets = new CopyOnWriteArrayList<>();
private final Collection<ShardingExecuteGroup<StatementExecuteUnit>> executeGroups = new LinkedList<>();
從這個類開始,我們會慢慢接觸到JDBC相關的對象,因爲ShardingSphere的設計目標是重寫一套與目前的JDBC規範完全兼容的體系。這裏,我們看到的Connection、Statement和ResultSet等對象都是屬於JDBC中的自帶對象,大家都很熟悉。其他的幾個參數如DatabaseType、ShardingConnection等也很重要,對它們的介紹過程中會涉及到sharding-jdbc-core中很多關於數據庫訪問相關的類的介紹,包括我們以前已經接觸過的ShardingStatement和ShardingPreparedStatement等類。我們在具體展開AbstractStatementExecutor類中的實現方法之前需要對這些類有一定的瞭解。
我們先來看一下DatabaseType接口,該接口代表數據庫類型,定義如下:
public interface DatabaseType {
String getName();
Collection<String> getJdbcUrlPrefixAlias();
DataSourceMetaData getDataSourceMetaData(String url, String username);
}
請注意DatabaseType接口位於sharding-core-api包中,而它的實現類位於具體的sharding-core-common包中,其類層結構如下所示:
其中以MySQLDatabaseType爲例,代碼如下所示:
public final class MySQLDatabaseType implements DatabaseType {
@Override
public String getName() {
return "MySQL";
}
@Override
public Collection<String> getJdbcUrlPrefixAlias() {
return Collections.singletonList("jdbc:mysqlx:");
}
@Override
public MySQLDataSourceMetaData getDataSourceMetaData(final String url, final String username) {
return new MySQLDataSourceMetaData(url);
}
}
上述代碼中的MySQLDataSourceMetaData實現了DataSourceMetaData接口,並提供如下所示的對輸入url的解析過程:
public MySQLDataSourceMetaData(final String url) {
Matcher matcher = pattern.matcher(url);
if (!matcher.find()) {
throw new UnrecognizedDatabaseURLException(url, pattern.pattern());
}
hostName = matcher.group(4);
port = Strings.isNullOrEmpty(matcher.group(5)) ? DEFAULT_PORT : Integer.valueOf(matcher.group(5));
catalog = matcher.group(6);
schema = null;
}
顯然,DatabaseType用於保存與特定數據庫元數據相關的信息。而ShardingSphere還提供了DatabaseTypes類來基於SPI機制實現對各種DatabaseType實例的動態管理,關於SPI機制可以回顧《ShardingSphere源碼解析之微內核架構(下)》中的內容。
然後,我們再來看AbstractStatementExecutor中的ShardingConnection類,這個類非常重要,是對JDBC中Connection的適配和包裝,所以它需要提供Connection接口中的方法,包括createConnection、getMetaData、各種重載的prepareStatement和createStatement以及針對事務的setAutoCommit、commit和rollback方法等,ShardingConnection對這些方法都進行了重寫,如下所示:
這裏面有很多關於事務處理方面的內容,我們後面會有專題進行講解,今天先不做展開。我們先關注ShardingConnection中如下所示的一個上下文對象:
private final ShardingRuntimeContext runtimeContext;
要講解ShardingRuntimeContext對象,就需要對它的類層結構進行詳細分析。我們發現在sharding-jdbc-core工程中包含了一個RuntimeContext接口,如下所示:
public interface RuntimeContext<T extends BaseRule> extends AutoCloseable {
T getRule();
ShardingProperties getProps();
DatabaseType getDatabaseType();
ShardingExecuteEngine getExecuteEngine();
SQLParseEngine getParseEngine();
}
可以看到,我們熟悉的SQL解析引擎SQLParseEngine和SQL執行引擎ShardingExecuteEngine都可以通過這個接口進行獲取,也就意味着在這個接口的實現類中應該包含了創建這些引擎的入口。同時,我們還看到了RuntimeContext 應該包含一個BaseRule接口的實現類,而我們前面介紹的ShardingRule和MasterSlaveRule都實現了這個BaseRule接口。
在sharding-jdbc-core工程中,RuntimeContext接口的實現都位於org.apache.shardingsphere.shardingjdbc.jdbc.core.context包中,其類層接口如下所示:
AbstractRuntimeContext這個抽象類實現了RuntimeContext接口,而ShardingRuntimeContext類又擴展了AbstractRuntimeContext,我們先來看AbstractRuntimeContext類。實際上這個類在介紹SQL引擎的第一篇文章《ShardingSphere源碼解析之SQL解析引擎(一)》中已經提到過,讓我們來回顧一下。AbstractRuntimeContext的構造函數中實現了SQLParseEngineFactory和ShardingExecuteEngine的創建,如下所示:
protected AbstractRuntimeContext(final T rule, final Properties props, final DatabaseType databaseType) {
this.rule = rule;
this.props = new ShardingProperties(null == props ? new Properties() : props);
this.databaseType = databaseType;
executeEngine = new ShardingExecuteEngine(this.props.<Integer>getValue(ShardingPropertiesConstant.EXECUTOR_SIZE));
parseEngine = SQLParseEngineFactory.getSQLParseEngine(DatabaseTypes.getTrunkDatabaseTypeName(databaseType));
ConfigurationLogger.log(rule.getRuleConfiguration());
ConfigurationLogger.log(props);
}
而在AbstractRuntimeContext的子類ShardingRuntimeContext中,主要工作是創建了與事務相關的ShardingTransactionManagerEngine以及兩個元數據對象DatabaseMetaData和ShardingSphereMetaData。同時這裏還存在一個TableMetaDataInitializer類用於加載表相關的元數據。這些元數據的管理都不屬於核心流程,所以不做詳細展開。
到目前爲止,與ShardingConnection相關的類結構如下圖所示,這是一條類層結構的支線,關注於ShardingConnection內部所包含對象的創建過程:
對於ShardingConnection而言,還有另一條類層結構支線,即作爲一種Connection對象所應該具備的基本結構,我們將在下一篇中對這個話題進行詳細展開。
更多內容可以關注我的公衆號:程序員向架構師轉型。