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

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

4.配置模块

每个MyCatServer初始化时,会初始化: MyCatServer.java:

public static final String NAME = "MyCat";private static final long LOG_WATCH_DELAY = 60000L;private static final long TIME_UPDATE_PERIOD = 20L;private static final MycatServer INSTANCE = new MycatServer();private static final Logger LOGGER = LoggerFactory.getLogger("MycatServer");private final RouteService routerService;private final CacheService cacheService;private Properties dnIndexProperties;//AIO连接群组private AsynchronousChannelGroup[] asyncChannelGroups;private volatile int channelIndex = 0;//全局序列号private final MyCATSequnceProcessor sequnceProcessor = new MyCATSequnceProcessor();private final DynaClassLoader catletClassLoader;private final SQLInterceptor sqlInterceptor;private volatile int nextProcessor;private BufferPool bufferPool;private boolean aio = false;//XA事务全局ID生成private final AtomicLong xaIDInc = new AtomicLong();private MycatServer() {    //读取文件配置
    this.config = new MycatConfig();    //定时线程池,单线程线程池
    scheduler = Executors.newSingleThreadScheduledExecutor();    //SQL记录器
    this.sqlRecorder = new SQLRecorder(config.getSystem()
            .getSqlRecordCount());    /**
     * 是否在线,MyCat manager中有命令控制
     * | offline | Change MyCat status to OFF |
     * | online | Change MyCat status to ON |
     */
    this.isOnline = new AtomicBoolean(true);    //缓存服务初始化
    cacheService = new CacheService();    //路由计算初始化
    routerService = new RouteService(cacheService);    // load datanode active index from properties
    dnIndexProperties = loadDnIndexProps();    try {        //SQL解析器
        sqlInterceptor = (SQLInterceptor) Class.forName(
                config.getSystem().getSqlInterceptor()).newInstance();
    } catch (Exception e) {        throw new RuntimeException(e);
    }    //catlet加载器
    catletClassLoader = new DynaClassLoader(SystemConfig.getHomePath()
            + File.separator + "catlet", config.getSystem()
            .getCatletClassCheckSeconds());    //记录启动时间
    this.startupTime = TimeUtil.currentTimeMillis();
}

第一步是读取文件配置,主要是三个文件:schema.xml,rule.xml和server.xml. 读取后的配置会加载到MyCatConfig中。 MyCatConfig.java:

public MycatConfig() {//读取schema.xml,rule.xml和server.xmlConfigInitializer confInit = new ConfigInitializer(true);this.system = confInit.getSystem();this.users = confInit.getUsers();this.schemas = confInit.getSchemas();this.dataHosts = confInit.getDataHosts();this.dataNodes = confInit.getDataNodes();for (PhysicalDBPool dbPool : dataHosts.values()) {
    dbPool.setSchemas(getDataNodeSchemasOfDataHost(dbPool.getHostName()));
}this.quarantine = confInit.getQuarantine();this.cluster = confInit.getCluster();//初始化重加载配置时间this.reloadTime = TimeUtil.currentTimeMillis();this.rollbackTime = -1L;this.status = RELOAD;//配置加载锁this.lock = new ReentrantLock();
}

它们都通过ConfigInitializer读取:

public ConfigInitializer(boolean loadDataHost) {    //读取schema.xml
    SchemaLoader schemaLoader = new XMLSchemaLoader();    //读取server.xml
    XMLConfigLoader configLoader = new XMLConfigLoader(schemaLoader);
    schemaLoader = null;    //加载配置
    this.system = configLoader.getSystemConfig();    this.users = configLoader.getUserConfigs();    this.schemas = configLoader.getSchemaConfigs();    //是否重新加载DataHost和对应的DataNode
    if (loadDataHost) {        this.dataHosts = initDataHosts(configLoader);        this.dataNodes = initDataNodes(configLoader);
    }    //权限管理
    this.quarantine = configLoader.getQuarantineConfig();    this.cluster = initCobarCluster(configLoader);    //不同类型的全局序列处理器的配置加载
    if (system.getSequnceHandlerType() == SystemConfig.SEQUENCEHANDLER_MYSQLDB) {
        IncrSequenceMySQLHandler.getInstance().load();
    }    if (system.getSequnceHandlerType() == SystemConfig.SEQUENCEHANDLER_LOCAL_TIME) {
        IncrSequenceTimeHandler.getInstance().load();
    }    //检查user与schema配置对应以及schema配置不为空
    this.checkConfig();
}

4.1 rule.xml

读取schema之前会先读取rule.xml。 XmlSchemaLoader.java:

public XMLSchemaLoader(String schemaFile, String ruleFile) {    //先读取rule.xml
    XMLRuleLoader ruleLoader = new XMLRuleLoader(ruleFile);    this.tableRules = ruleLoader.getTableRules();
    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);
}public XMLSchemaLoader() {    this(null, null);
}

XMLRuleLoader.java:

public XMLRuleLoader(String ruleFile) {    // this.rules = new HashSet<RuleConfig>();
    //rule名 -> rule
    this.tableRules = new HashMap<String, TableRuleConfig>();    //function名 -> 具体分片算法
    this.functions = new HashMap<String, AbstractPartitionAlgorithm>();    //默认为:/rule.dtd和/rule.xml
    load(DEFAULT_DTD, ruleFile == null ? DEFAULT_XML : ruleFile);
}public XMLRuleLoader() {    this(null);
}
private void load(String dtdFile, String xmlFile) {
    InputStream dtd = null;
    InputStream xml = null;    try {
        dtd = XMLRuleLoader.class.getResourceAsStream(dtdFile);
        xml = XMLRuleLoader.class.getResourceAsStream(xmlFile);        //读取出语意树
        Element root = ConfigUtil.getDocument(dtd, xml)
                .getDocumentElement();        //加载Function
        loadFunctions(root);        //加载TableRule
        loadTableRules(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) {
            }
        }
    }
}

ConfigUtil.java解析语意树:

public static Document getDocument(final InputStream dtd, InputStream xml) throws ParserConfigurationException,
            SAXException, IOException {
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setValidating(true);
    factory.setNamespaceAware(false);
    DocumentBuilder builder = factory.newDocumentBuilder();
    builder.setEntityResolver(new EntityResolver() {        @Override
        public InputSource resolveEntity(String publicId, String systemId) {            return new InputSource(dtd);
        }
    });
    builder.setErrorHandler(new ErrorHandler() {        @Override
        public void warning(SAXParseException e) {
        }        @Override
        public void error(SAXParseException e) throws SAXException {            throw e;
        }        @Override
        public void fatalError(SAXParseException e) throws SAXException {            throw e;
        }
    });    return builder.parse(xml);
}

加载functions,XmlRuleLoader.java

private void loadFunctions(Element root) throws ClassNotFoundException,
            InstantiationException, IllegalAccessException,
            InvocationTargetException {
        NodeList list = root.getElementsByTagName("function");        for (int i = 0, n = list.getLength(); i < n; ++i) {
            Node node = list.item(i);            if (node instanceof Element) {
                Element e = (Element) node;                //获取name标签
                String name = e.getAttribute("name");                //如果Map已有,则function重复
                if (functions.containsKey(name)) {                    throw new ConfigException("rule function " + name
                            + " duplicated!");
                }                //获取class标签
                String clazz = e.getAttribute("class");                //根据class利用反射新建分片算法
                AbstractPartitionAlgorithm function = createFunction(name, clazz);                 ParameterMapping.mapping(function, ConfigUtil.loadElements(e));                //每个AbstractPartitionAlgorithm可能会实现init来初始化
                function.init();                //放入functions map
                functions.put(name, function);
            }
        }
    }private AbstractPartitionAlgorithm createFunction(String name, String clazz)
        throws ClassNotFoundException, InstantiationException,
        IllegalAccessException, InvocationTargetException {
    Class<?> clz = Class.forName(clazz);    //判断是否继承AbstractPartitionAlgorithm
    if (!AbstractPartitionAlgorithm.class.isAssignableFrom(clz)) {        throw new IllegalArgumentException("rule function must implements "
                + AbstractPartitionAlgorithm.class.getName() + ", name=" + name);
    }
    return (AbstractPartitionAlgorithm) clz.newInstance();
}

加载所有的function的node,每一个node就是一个AbstractPartitionAlgorithm,并放入functions这个map中;

private final Map<String, TableRuleConfig> tableRules;

对于每一个node,通过反射新建对应参数的AbstractPartitionAlgorithm。这样,所有的function就加载到了functions这个map中。
同理,加载TableRule,就加上了function是否存在的判断:

/**
* tableRule标签结构:
 * <tableRule name="sharding-by-month">
 *     <rule>
 *         <columns>create_date</columns>
 *         <algorithm>partbymonth</algorithm>
 *     </rule>
 * </tableRule>
 * @param root
 * @throws SQLSyntaxErrorException
    */private void loadTableRules(Element root) throws SQLSyntaxErrorException {    //获取每个tableRule标签
    NodeList list = root.getElementsByTagName("tableRule");    for (int i = 0, n = list.getLength(); i < n; ++i) {
        Node node = list.item(i);        if (node instanceof Element) {
            Element e = (Element) node;            //先判断是否重复
            String name = e.getAttribute("name");            if (tableRules.containsKey(name)) {                throw new ConfigException("table rule " + name
                        + " duplicated!");
            }            //获取rule标签

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

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

相关文章:
【推荐】 JAVA异常的最佳工程学实践探索
【推荐】 深入解析SQL Server高可用镜像实现原理

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

  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 - 源代码篇(17)

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

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

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

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

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

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

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

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

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

随机推荐

  1. CNN延拓至 复数域

  2. apache 301重定向到带www的二级域名

    Options +FollowSymlinks RewriteEngine on rewritecond %{http_host} ^nlike.cn [nc] rewriterule ^(.*)$ ...

  3. 一起来学linux:例行性任务之at和crontab

    对于我们日常生活来说,有很多例行需要进行的工作,比如每天早上起床一杯水,例如家人的生日,每天的起床时间等.这性例行的工作有可能被遗忘,但是如果我们用计算机来进行提醒的话,则方便很多.这里就要介绍到Li ...

  4. discuz论坛搬家

    很多站长第一次做网站的时候,无奈选择了速度不是很稳定的空间,慢慢会发现有很多物美价廉速度相当快的空间 这个时候,站长在网站搬家的过程中就会遇到很多困难,今天老袋鼠给大家详细讲解一下discuz论坛搬家 ...

  5. elasticsearch 简单聚合查询示例

    因为懒癌犯了,查询语句使用的截图而不是文字,导致了发布随笔的时候提示少于150字的随笔不能发布. 我就很郁闷了. 下面的查询都是前段时间工作中使用过的查询语句. 开始的时候是使用nodejs构建es查 ...

  6. eslint 配合 git (husky)

    为了保证每次提交的 git 代码是正确的,为此我们可以使用 eslint 配合 git hook, 在进行git commit 的时候验证eslint规范 如果 eslint 验证不通过,则不能提交. ...

  7. jsp九大内置对象和其作用详解

    jsp九大内置对象和其作用详解 JSP中一共预先定义了9个这样的对象,分别为:request.response.session.application.out.pagecontext.config.p ...

  8. kvm初体验之八:调整vm的vcpu, memory, disk大小

    假设host上创建的vm的名字为vm1. 1. 查看vm1的domain information [root@tanghuimin thm]# virsh dominfo vm1 Id: 10 Nam ...

  9. linux 加密解密文件小程序

    代码见下面,编译之后就可以用:建议放在bash下,或者添加环境变量. 使用方法:encrypt .两次输入密码.加密密码与解密密码不一致解码后就不是原文件了! #include <stdio.h ...

  10. 关系逻辑运算符---------&&和||

    1.&&符号 常规用法没什么好说的,我们来说说其不同于java的特殊之处 (1)&&符号究竟返回什么 我们知道,0,null,defined,null,NaN等都可以转 ...