四、MyCat|四、MyCat 初始化

MyCat 初始化主要负责启动 MycatServer 实例,启动 MycatServer 实例的过程中,核心工作是读取并解析 Mycat 配置文件(schema.xml、rule.xml 和 server.xml)。MycatServer 使用”饿汉模式“初始化一个单例

public class MycatServer { private static final MycatServer INSTANCE = new MycatServer(); public static final MycatServer getInstance() { return INSTANCE; }private MycatServer() { // 读取文件配置 this.config = new MycatConfig(); ... } }

读取并解析 MyCat 配置文件的具体实现交由 MycatConfigMycatConfig 内部使用 ConfigInitializer 解析全局配置。ConfigInitializer 主要处理一下几件事情:
  1. 读取 schema.xml、rule.xml 和 server.xml 文件并将解析到的配置类赋给 ConfigInitializer 的变量中
  2. 解析 DataHost 和对应的 DataNode,创建物理数据库连接池(PhysicalDBPool)和物理数据库节点(PhysicalDBNode)
  3. 权限管理设置
  4. 加载全局序列处理器配置
  5. 配置文件自检
在此我重点叙述 1 和 2
4.1 配置文件读取
// 读取 rule.xml和schema.xml SchemaLoader schemaLoader = new XMLSchemaLoader(); // 读取 server.xml XMLConfigLoader configLoader = new XMLConfigLoader(schemaLoader);

4.2 创建物理数据库连接池(PhysicalDBPool) 【四、MyCat|四、MyCat 初始化】initDataHosts 为每一个 节点创建一个数据库连接池,创建完成后返回 Map physicalDBPoolMap,其中 key 为 节点的 name 属性值,value 为 节点对应的数据库连接池
private Map initDataHosts(ConfigLoader configLoader) { Map dataHostConfigMap = configLoader.getDataHosts(); Map physicalDBPoolMap = new HashMap<>(dataHostConfigMap.size()); for (DataHostConfig dataHostConfig : dataHostConfigMap.values()) { // 为每个 dataHost 节点建立一个 PhysicalDBPool PhysicalDBPool pool = getPhysicalDBPool(dataHostConfig, configLoader); physicalDBPoolMap.put(pool.getHostName(), pool); } return physicalDBPoolMap; }

io.mycat.config.ConfigInitializer#getPhysicalDBPool 方法为每个 节点建立一个 PhysicalDBPool,主要工作如下:
  1. 为每一个 节点的 < writeHost> 节点创建一个 PhysicalDatasource
  2. 为每一个 节点的 节点创建一个 PhysicalDatasource
  3. 初始化 PhysicalDBPool 并返回
private PhysicalDBPool getPhysicalDBPool(DataHostConfig dataHostConfig, ConfigLoader configLoader) { // dataHost 节点名 String name = dataHostConfig.getName(); // 数据库类型,我们这里只讨论MySQL String dbType = dataHostConfig.getDbType(); // 连接数据库驱动,我们这里只讨论 MyCat 自己实现的 native String dbDriver = dataHostConfig.getDbDriver(); // 1 为每一个 节点的 节点创建一个 PhysicalDatasource PhysicalDatasource[] writeSources = createDataSource(dataHostConfig, name, dbType, dbDriver, dataHostConfig.getWriteHosts(), false); Map readHostsMap = dataHostConfig.getReadHosts(); Map readSourcesMap = new HashMap(readHostsMap.size()); // 对于每个读节点建立 key 为 writeHost 下标 value 为 readHost 的 PhysicalDatasource[] 的哈希表 for (Map.Entry entry : readHostsMap.entrySet()) { // 2 为每一个 节点的 节点创建一个 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 完成具体的数据源创建。根据不同的 dvTypedbDriver 创建不同的 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++) { //设置最大 idle 时间,默认为 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 创建物理数据库节点(PhysicalDBNode) io.mycat.config.ConfigInitializer#initDataNodes 为每个 节点创建一个 PhysicalDBNode,根据 节点的 dataHost 属性值从 Map dataHosts 中找到 对应的连接池,并赋予 PhysicalDBNode
private Map initDataNodes(ConfigLoader configLoader) { Map nodes = new HashMap(dataNodeConfigMap.size()); Map dataNodeConfigMap = configLoader.getDataNodes(); for (DataNodeConfig dataNodeConfig : dataNodeConfigMap.values()) { // 根据 dataHost 名称获取对应的 PhysicalDBPool PhysicalDBPool pool = this.dataHosts.get(dataNodeConfig.getDataHost()); PhysicalDBNode dataNode = new PhysicalDBNode(dataNodeConfig.getName(), dataNodeConfig.getDatabase(), pool); nodes.put(dataNode.getName(), dataNode); } return nodes; }

    推荐阅读