此文已由作者张镐薪授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。

NodeList ruleNodes = e.getElementsByTagName("rule");
            int length = ruleNodes.getLength();
            if (length > 1) {
                throw new ConfigException("only one rule can defined :"
                        + name);
            }
            //目前只处理第一个,未来可能有多列复合逻辑需求
            //RuleConfig是保存着rule与function对应关系的对象
            RuleConfig rule = loadRule((Element) ruleNodes.item(0));
            String funName = rule.getFunctionName();
            //判断function是否存在,获取function
            AbstractPartitionAlgorithm func = functions.get(funName);
            if (func == null) {
                throw new ConfigException("can't find function of name :"
                        + funName);
            }
            rule.setRuleAlgorithm(func);
            //保存到tableRules
            tableRules.put(name, new TableRuleConfig(name, rule));
        }
    }
}

这样,所有的tableRule和function就加载完毕。保存在一个变量中,就是tableRules:XMLRuleLoader.java:

private final Map<String, TableRuleConfig> tableRules;

4.2 schema.xml:

public XMLSchemaLoader(String schemaFile, String ruleFile) {    //先读取rule.xml
    XMLRuleLoader ruleLoader = new XMLRuleLoader(ruleFile);    //将tableRules拿出,用于这里加载Schema做rule有效判断,以及之后的分片路由计算
    this.tableRules = ruleLoader.getTableRules();    //释放ruleLoader
    ruleLoader = null;    this.dataHosts = new HashMap<String, DataHostConfig>();    this.dataNodes = new HashMap<String, DataNodeConfig>();    this.schemas = new HashMap<String, SchemaConfig>();    //读取加载schema配置
    this.load(DEFAULT_DTD, schemaFile == null ? DEFAULT_XML : schemaFile);
}private void load(String dtdFile, String xmlFile) {
    InputStream dtd = null;
    InputStream xml = null;    try {
        dtd = XMLSchemaLoader.class.getResourceAsStream(dtdFile);
        xml = XMLSchemaLoader.class.getResourceAsStream(xmlFile);
        Element root = ConfigUtil.getDocument(dtd, xml).getDocumentElement();        //先加载所有的DataHost
        loadDataHosts(root);        //再加载所有的DataNode
        loadDataNodes(root);        //最后加载所有的Schema
        loadSchemas(root);
    } catch (ConfigException e) {        throw e;
    } catch (Exception e) {        throw new ConfigException(e);
    } finally {        if (dtd != null) {            try {
                dtd.close();
            } catch (IOException e) {
            }
        }        if (xml != null) {            try {
                xml.close();
            } catch (IOException e) {
            }
        }
    }
}

先看下DataHostConfig这个类的结构: XMLSchemaLoader.java:

private void loadDataHosts(Element root) {
    NodeList list = root.getElementsByTagName("dataHost");    for (int i = 0, n = list.getLength(); i < n; ++i) {         Element element = (Element) list.item(i);
        String name = element.getAttribute("name");        //判断是否重复
        if (dataHosts.containsKey(name)) {            throw new ConfigException("dataHost name " + name + "duplicated!");
        }        //读取最大连接数
        int maxCon = Integer.valueOf(element.getAttribute("maxCon"));        //读取最小连接数
        int minCon = Integer.valueOf(element.getAttribute("minCon"));        /**
         * 读取负载均衡配置
         * 1. balance="0", 不开启分离机制,所有读操作都发送到当前可用的 writeHost 上。
         * 2. balance="1",全部的 readHost 和 stand by writeHost 参不 select 的负载均衡
         * 3. balance="2",所有读操作都随机的在 writeHost、readhost 上分发。
         * 4. balance="3",所有读请求随机的分发到 wiriterHost 对应的 readhost 执行,writerHost 不负担读压力
         */
        int balance = Integer.valueOf(element.getAttribute("balance"));        /**
         * 读取切换类型
         * -1 表示不自动切换
         * 1 默认值,自动切换
         * 2 基于MySQL主从同步的状态决定是否切换
         * 心跳询句为 show slave status
         * 3 基于 MySQL galary cluster 的切换机制
         */
        String switchTypeStr = element.getAttribute("switchType");        int switchType = switchTypeStr.equals("") ? -1 : Integer.valueOf(switchTypeStr);        //读取从延迟界限
        String slaveThresholdStr = element.getAttribute("slaveThreshold");        int slaveThreshold = slaveThresholdStr.equals("") ? -1 : Integer.valueOf(slaveThresholdStr);        //如果 tempReadHostAvailable 设置大于 0 则表示写主机如果挂掉, 临时的读服务依然可用
        String tempReadHostAvailableStr = element.getAttribute("tempReadHostAvailable");
        boolean tempReadHostAvailable = tempReadHostAvailableStr.equals("") ? false : Integer.valueOf(tempReadHostAvailableStr) > 0;        /**
         * 读取 写类型
         * 这里只支持 0 - 所有写操作仅配置的第一个 writeHost
         */
        String writeTypStr = element.getAttribute("writeType");        int writeType = "".equals(writeTypStr) ? PhysicalDBPool.WRITE_ONLYONE_NODE : Integer.valueOf(writeTypStr);         String dbDriver = element.getAttribute("dbDriver");
        String dbType = element.getAttribute("dbType");
        String filters = element.getAttribute("filters");
        String logTimeStr = element.getAttribute("logTime");        long logTime = "".equals(logTimeStr) ? PhysicalDBPool.LONG_TIME : Long.valueOf(logTimeStr) ;        //读取心跳语句
        String heartbeatSQL = element.getElementsByTagName("heartbeat").item(0).getTextContent();        //读取 初始化sql配置,用于oracle
        NodeList connectionInitSqlList = element.getElementsByTagName("connectionInitSql");
        String initConSQL = null;        if (connectionInitSqlList.getLength() > 0) {
            initConSQL = connectionInitSqlList.item(0).getTextContent();
        }        //读取writeHost
        NodeList writeNodes = element.getElementsByTagName("writeHost");
        DBHostConfig[] writeDbConfs = new DBHostConfig[writeNodes.getLength()];
        Map<Integer, DBHostConfig[]> readHostsMap = new HashMap<Integer, DBHostConfig[]>(2);        for (int w = 0; w < writeDbConfs.length; w++) {
            Element writeNode = (Element) writeNodes.item(w);
            writeDbConfs[w] = createDBHostConf(name, writeNode, dbType, dbDriver, maxCon, minCon,filters,logTime);
            NodeList readNodes = writeNode.getElementsByTagName("readHost");            //读取对应的每一个readHost
            if (readNodes.getLength() != 0) {
                DBHostConfig[] readDbConfs = new DBHostConfig[readNodes.getLength()];                for (int r = 0; r < readDbConfs.length; r++) {
                    Element readNode = (Element) readNodes.item(r);
                    readDbConfs[r] = createDBHostConf(name, readNode, dbType, dbDriver, maxCon, minCon,filters, logTime);
                }
                readHostsMap.put(w, readDbConfs);
            }
        }         DataHostConfig hostConf = new DataHostConfig(name, dbType, dbDriver, 
                writeDbConfs, readHostsMap, switchType, slaveThreshold, tempReadHostAvailable);                 hostConf.setMaxCon(maxCon);
        hostConf.setMinCon(minCon);
        hostConf.setBalance(balance);
        hostConf.setWriteType(writeType);
        hostConf.setHearbeatSQL(heartbeatSQL);
        hostConf.setConnectionInitSql(initConSQL);
        hostConf.setFilters(filters);
        hostConf.setLogTime(logTime);
        dataHosts.put(hostConf.getName(), hostConf);
    }
}

先读取每个DataHost的通用配置,之后读取每个DataHost对应的writeHost以及每个writeHost对应的readHost。配置好后,保存在:

private final Map<String, DataHostConfig> dataHosts;

之后读取载入DataHost: XMLSchemaLoader.java:

private void loadDataNodes(Element root) {    //读取DataNode分支
    NodeList list = root.getElementsByTagName("dataNode");    for (int i = 0, n = list.getLength(); i < n; i++) {
        Element element = (Element) list.item(i);
        String dnNamePre = element.getAttribute("name");         String databaseStr = element.getAttribute("database");
        String host = element.getAttribute("dataHost");        //字符串不为空
        if (empty(dnNamePre) || empty(databaseStr) || empty(host)) {            throw new ConfigException("dataNode " + dnNamePre + " define error ,attribute can't be empty");
        }        //dnNames(name),databases(database),hostStrings(dataHost)都可以配置多个,以',', '$', '-'区分,但是需要保证database的个数*dataHost的个数=name的个数
        //多个dataHost与多个database如果写在一个标签,则每个dataHost拥有所有database
        //例如:<dataNode name="dn1$0-75" dataHost="localhost$1-10" database="db$0-759" />
        //则为:localhost1拥有dn1$0-75,localhost2也拥有dn1$0-75(对应db$76-151)
        String[] dnNames = io.mycat.util.SplitUtil.split(dnNamePre, ',', '$', '-');
        String[] databases = io.mycat.util.SplitUtil.split(databaseStr, ',', '$', '-');
        String[] hostStrings = io.mycat.util.SplitUtil.split(host, ',', '$', '-');        if (dnNames.length > 1 && dnNames.length != databases.length * hostStrings.length) {            throw new ConfigException("dataNode " + dnNamePre
                            + " define error ,dnNames.length must be=databases.length*hostStrings.length");
        }        if (dnNames.length > 1) {             List<String[]> mhdList = mergerHostDatabase(hostStrings, databases);            for (int k = 0; k < dnNames.length; k++) {
                String[] hd = mhdList.get(k);
                String dnName = dnNames[k];
                String databaseName = hd[1];
                String hostName = hd[0];
                createDataNode(dnName, databaseName, hostName);
            }         } else {
            createDataNode(dnNamePre, databaseStr, host);
        }     }
}private void createDataNode(String dnName, String database, String host) {     DataNodeConfig conf = new DataNodeConfig(dnName, database, host);        
    if (dataNodes.containsKey(conf.getName())) {        throw new ConfigException("dataNode " + conf.getName() + " duplicated!");
    }    if (!dataHosts.containsKey(host)) {        throw new ConfigException("dataNode " + dnName + " reference dataHost:" + host + " not exists!");
    }
    dataNodes.put(conf.getName(), conf);
}

生成的是DataNode类,放入:

private final Map<String, DataNodeConfig> dataNodes;

免费体验云安全(易盾)内容安全、验证码等服务

更多网易技术、产品、运营经验分享请点击

相关文章:
【推荐】 网易容器云平台的微服务化实践(一)
【推荐】 如何实现360度的手游安全防护?网易云易盾专家分享最新实践
【推荐】 一个只有十行的精简MVVM框架(上篇)

数据库路由中间件MyCat - 源代码篇(12)的更多相关文章

  1. 数据库路由中间件MyCat - 源代码篇(1)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 进入了源代码篇,我们先从整体入手,之后拿一个简单流程前端连接建立与认证作为例子,理清代码思路和设计模式.然后 ...

  2. 数据库路由中间件MyCat - 源代码篇(13)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 4.配置模块 4.2 schema.xml 接上一篇,接下来载入每个schema的配置(也就是每个MyCat ...

  3. 数据库路由中间件MyCat - 源代码篇(7)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 3. 连接模块 3.4 FrontendConnection前端连接 构造方法: public Fronte ...

  4. 数据库路由中间件MyCat - 源代码篇(15)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. public static void handle(String stmt, ServerConnectio ...

  5. 数据库路由中间件MyCat - 源代码篇(2)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 2. 前端连接建立与认证 Title:MySql连接建立以及认证过程client->MySql:1.T ...

  6. 数据库路由中间件MyCat - 源代码篇(17)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 调用processInsert(sc,schema,sqlType,origSQL,tableName,pr ...

  7. 数据库路由中间件MyCat - 源代码篇(14)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 对于表的dataNode对应关系,有个特殊配置即类似dataNode="distributed(d ...

  8. 数据库路由中间件MyCat - 源代码篇(4)

    此文已由作者易国强授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 2. 前端连接建立与认证 Title:MySql连接建立以及认证过程client->MySql:1.T ...

  9. 数据库路由中间件MyCat - 源代码篇(16)

    此文已由作者张镐薪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 5. 路由模块 真正取得RouteResultset的步骤:AbstractRouteStrategy的ro ...

随机推荐

  1. lvs虚拟服务器

    NAT模式 1.模拟环境: LVS服务器有两块网卡,连接外网(用户端)和内网(服务器),充当"交警"角色. 优点: 节省ip开销 缺点: LVS服务器负载过高,数据吞吐量降低 三台 ...

  2. 我的Java开发学习之旅------>Java经典排序算法之归并排序

    一.归并排序 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序列:即先使每个子序列 ...

  3. (转)ARCGIS中坐标转换及地理坐标、投影坐标的定义

    原文地址:http://blog.sina.com.cn/s/blog_663d9a1f01017cyz.html 1.动态投影(ArcMap) 所谓动态投影指,ArcMap中的Data 的空间参考或 ...

  4. tmux基本使用方法

    tmux是一款优秀的终端复用软件.tmux采用C/S模型构建,输入tmux命令就相当于开启了一个服务器,此时默认将新建一个会话,然后会话中默认新建一个窗口,窗口中默认新建一个面板. 一个tmux se ...

  5. springcloud 研发规范

    1) 程序结构规范 1: Facade-Stub:包含所有对外提供服务的借口定义,并对外提供 2:  Façade:实现Façade-Stub里面定义的全部借口,可以调用Service模块和Commo ...

  6. POJ 之 WERTYU

    WERTYU Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8371   Accepted: 4007 Descriptio ...

  7. Appium——api常用函数

    appium常用函数介绍:   获取页面信息:   1. def get_current_activity(cls, driver): ''' 获取当前页面的activity :param drive ...

  8. 51nod 80分算法题

    1537:见前几篇. 1627:题意:给定n,m的网格(10^5),初始状态为(1,1),你每次可以瞬移到右下方(不可以同行同列逗留)任何一个方格里,求移动到n,m的方案数. 一句话题解:首先很容易想 ...

  9. Hadoop- 集群时间同步

    集群的时间要同步 * 找一台机器 时间服务器 * 所有的机器与这台机器时间进行定时的同步 比如,每日十分钟,同步一次时间 # rpm -qa|grep ntp # vi /etc/ntp.conf # ...

  10. 如何在VMware Workstation上安装CentOS_7

    1.首先打开VMware Workstation-文件-新建虚拟机 2.选择自定义向导,下一步. 3.由于我的软件版本比较高,不想太多硬件限制就选了版本11.也可以选择低一些版本的,这样兼容性会更好, ...