MyCat 初始化主要負(fù)責(zé)啟動 MycatServer
實(shí)例,啟動 MycatServer
實(shí)例的過程中聚唐,核心工作是讀取并解析 Mycat 配置文件(schema.xml丐重、rule.xml 和 server.xml)。MycatServer
使用”餓漢模式“初始化一個(gè)單例
public class MycatServer {
private static final MycatServer INSTANCE = new MycatServer();
public static final MycatServer getInstance() {
return INSTANCE;
}
private MycatServer() {
// 讀取文件配置
this.config = new MycatConfig();
...
}
}
讀取并解析 MyCat 配置文件的具體實(shí)現(xiàn)交由 MycatConfig
杆查。MycatConfig
內(nèi)部使用 ConfigInitializer
解析全局配置扮惦。ConfigInitializer
主要處理一下幾件事情:
- 讀取 schema.xml、rule.xml 和 server.xml 文件并將解析到的配置類賦給 ConfigInitializer 的變量中
- 解析 DataHost 和對應(yīng)的 DataNode亲桦,創(chuàng)建物理數(shù)據(jù)庫連接池(PhysicalDBPool)和物理數(shù)據(jù)庫節(jié)點(diǎn)(PhysicalDBNode)
- 權(quán)限管理設(shè)置
- 加載全局序列處理器配置
- 配置文件自檢
在此我重點(diǎn)敘述 1 和 2
4.1 配置文件讀取
// 讀取 rule.xml和schema.xml
SchemaLoader schemaLoader = new XMLSchemaLoader();
// 讀取 server.xml
XMLConfigLoader configLoader = new XMLConfigLoader(schemaLoader);
4.2 創(chuàng)建物理數(shù)據(jù)庫連接池(PhysicalDBPool)
initDataHosts
為每一個(gè) <dataHost>
節(jié)點(diǎn)創(chuàng)建一個(gè)數(shù)據(jù)庫連接池崖蜜,創(chuàng)建完成后返回 Map<String, PhysicalDBPool> physicalDBPoolMap
,其中 key 為 <dataHost>
節(jié)點(diǎn)的 name 屬性值客峭,value 為 <dataHost>
節(jié)點(diǎn)對應(yīng)的數(shù)據(jù)庫連接池
private Map<String, PhysicalDBPool> initDataHosts(ConfigLoader configLoader) {
Map<String, DataHostConfig> dataHostConfigMap = configLoader.getDataHosts();
Map<String, PhysicalDBPool> physicalDBPoolMap = new HashMap<>(dataHostConfigMap.size());
for (DataHostConfig dataHostConfig : dataHostConfigMap.values()) {
// 為每個(gè) dataHost 節(jié)點(diǎn)建立一個(gè) PhysicalDBPool
PhysicalDBPool pool = getPhysicalDBPool(dataHostConfig, configLoader);
physicalDBPoolMap.put(pool.getHostName(), pool);
}
return physicalDBPoolMap;
}
io.mycat.config.ConfigInitializer#getPhysicalDBPool
方法為每個(gè) <dataHost>
節(jié)點(diǎn)建立一個(gè) PhysicalDBPool
豫领,主要工作如下:
- 為每一個(gè)
<dataHost>
節(jié)點(diǎn)的< writeHost>
節(jié)點(diǎn)創(chuàng)建一個(gè)PhysicalDatasource
- 為每一個(gè)
<dataHost>
節(jié)點(diǎn)的<readHost>
節(jié)點(diǎn)創(chuàng)建一個(gè)PhysicalDatasource
- 初始化
PhysicalDBPool
并返回
private PhysicalDBPool getPhysicalDBPool(DataHostConfig dataHostConfig, ConfigLoader configLoader) {
// dataHost 節(jié)點(diǎn)名
String name = dataHostConfig.getName();
// 數(shù)據(jù)庫類型,我們這里只討論MySQL
String dbType = dataHostConfig.getDbType();
// 連接數(shù)據(jù)庫驅(qū)動舔琅,我們這里只討論 MyCat 自己實(shí)現(xiàn)的 native
String dbDriver = dataHostConfig.getDbDriver();
// 1 為每一個(gè) <dataHost> 節(jié)點(diǎn)的 <writeHost> 節(jié)點(diǎn)創(chuàng)建一個(gè) PhysicalDatasource
PhysicalDatasource[] writeSources = createDataSource(dataHostConfig, name, dbType, dbDriver, dataHostConfig.getWriteHosts(), false);
Map<Integer, DBHostConfig[]> readHostsMap = dataHostConfig.getReadHosts();
Map<Integer, PhysicalDatasource[]> readSourcesMap = new HashMap<Integer, PhysicalDatasource[]>(readHostsMap.size());
// 對于每個(gè)讀節(jié)點(diǎn)建立 key 為 writeHost 下標(biāo) value 為 readHost 的 PhysicalDatasource[] 的哈希表
for (Map.Entry<Integer, DBHostConfig[]> entry : readHostsMap.entrySet()) {
// 2 為每一個(gè) <dataHost> 節(jié)點(diǎn)的 <readHost> 節(jié)點(diǎn)創(chuàng)建一個(gè) PhysicalDatasource
PhysicalDatasource[] readSources = createDataSource(dataHostConfig, name, dbType, dbDriver, entry.getValue(), true);
readSourcesMap.put(entry.getKey(), readSources);
}
// 3 初始化 PhysicalDBPool 并返回
PhysicalDBPool pool = new PhysicalDBPool(dataHostConfig.getName(), dataHostConfig, writeSources, readSourcesMap, dataHostConfig.getBalance(), dataHostConfig.getWriteType());
pool.setSlaveIDs(dataHostConfig.getSlaveIDs());
return pool;
}
io.mycat.config.ConfigInitializer#createDataSource
完成具體的數(shù)據(jù)源創(chuàng)建等恐。根據(jù)不同的 dvType
和 dbDriver
創(chuàng)建不同的 PhysicalDatasource
:
- dvType == mysql && dbDriver == native --> MySQLDataSource
- dvType == mysql && dbDriver == jdbc --> JDBCDataSource
- dvType == postgresql && dbDriver == native --> PostgreSQLDataSource
private PhysicalDatasource[] createDataSource(DataHostConfig dataHostConfig, String hostName, String dbType, String dbDriver, DBHostConfig[] nodes, boolean isRead) {
PhysicalDatasource[] dataSources = new PhysicalDatasource[nodes.length];
if ("mysql".equals(dbType) && "native".equals(dbDriver)) {
for (int i = 0; i < nodes.length; i++) {
//設(shè)置最大 idle 時(shí)間,默認(rèn)為 30 分鐘(可自定義)
nodes[i].setIdleTimeout(system.getIdleTimeout());
MySQLDataSource ds = new MySQLDataSource(nodes[i], dataHostConfig, isRead);
dataSources[i] = ds;
}
} else if ("jdbc".equals(dbDriver)) {
for (int i = 0; i < nodes.length; i++) {
nodes[i].setIdleTimeout(system.getIdleTimeout());
JDBCDatasource ds = new JDBCDatasource(nodes[i], dataHostConfig, isRead);
dataSources[i] = ds;
}
} else if ("postgresql".equalsIgnoreCase(dbType) && dbDriver.equalsIgnoreCase("native")) {
for (int i = 0; i < nodes.length; i++) {
nodes[i].setIdleTimeout(system.getIdleTimeout());
PostgreSQLDataSource ds = new PostgreSQLDataSource(nodes[i], dataHostConfig, isRead);
dataSources[i] = ds;
}
} else {
throw new ConfigException("not supported yet !" + hostName);
}
return dataSources;
}
4.3 創(chuàng)建物理數(shù)據(jù)庫節(jié)點(diǎn)(PhysicalDBNode)
io.mycat.config.ConfigInitializer#initDataNodes
為每個(gè) <dataNode>
節(jié)點(diǎn)創(chuàng)建一個(gè) PhysicalDBNode备蚓,根據(jù) <dataNode>
節(jié)點(diǎn)的 dataHost
屬性值從 Map<String, PhysicalDBPool> dataHosts
中找到 <dataNode>
對應(yīng)的連接池课蔬,并賦予 PhysicalDBNode
private Map<String, PhysicalDBNode> initDataNodes(ConfigLoader configLoader) {
Map<String, PhysicalDBNode> nodes = new HashMap<String, PhysicalDBNode>(dataNodeConfigMap.size());
Map<String, DataNodeConfig> dataNodeConfigMap = configLoader.getDataNodes();
for (DataNodeConfig dataNodeConfig : dataNodeConfigMap.values()) {
// 根據(jù) dataHost 名稱獲取對應(yīng)的 PhysicalDBPool
PhysicalDBPool pool = this.dataHosts.get(dataNodeConfig.getDataHost());
PhysicalDBNode dataNode = new PhysicalDBNode(dataNodeConfig.getName(), dataNodeConfig.getDatabase(), pool);
nodes.put(dataNode.getName(), dataNode);
}
return nodes;
}