小型培训机构网站开发毕业设计,浙江网站建设推广公司,网页 网站 区别,网站建设中页面html1. 简介
上一篇文章分析了集群容错的第一部分 – 服务目录 Directory。服务目录在刷新 Invoker 列表的过程中#xff0c;会通过 Router 进行服务路由。上一篇文章关于服务路由相关逻辑没有细致分析#xff0c;一笔带过了#xff0c;本篇文章将对此进行详细的分析。首先会通过 Router 进行服务路由。上一篇文章关于服务路由相关逻辑没有细致分析一笔带过了本篇文章将对此进行详细的分析。首先先来介绍一下服务目录是什么。服务路由包含一条路由规则路由规则决定了服务消费者的调用目标即规定了服务消费者可调用哪些服务提供者。Dubbo 目前提供了三种服务路由实现分别为条件路由 ConditionRouter、脚本路由 ScriptRouter 和标签路由 TagRouter。其中条件路由是我们最常使用的标签路由暂未在我所分析的 2.6.4 版本中提供该实现会在 2.7.0 版本中提供。本篇文章将分析条件路由相关源码脚本路由和标签路由这里就不分析了。下面进入正题。
2. 源码分析
条件路由规则有两个条件组成分别用于对服务消费者和提供者进行匹配。比如有这样一条规则
host 10.20.153.10 host 10.20.153.11
该条规则表示 IP 为 10.20.153.10 的服务消费者只可调用 IP 为 10.20.153.11 机器上的服务不可调用其他机器上的服务。条件路由规则的格式如下
[服务消费者匹配条件] [服务提供者匹配条件]
如果服务消费者匹配条件为空表示不对服务消费者进行限制。如果服务提供者匹配条件为空表示对某些服务消费者禁用服务。Dubbo 官方文档对条件路由进行了比较详细的介绍大家可以参考下这里就不过多说明了。
条件路由实现类 ConditionRouter 需要对用户配置的路由规则进行解析得到一系列的条件。然后再根据这些条件对服务进行路由。本章将分两节进行说明2.1节介绍表达式解析过程。2.2 节介绍服务路由的过程。接下来我们先从表达式解析过程看起。
2.1 表达式解析
条件路由规则是一条字符串对于 Dubbo 来说它并不能直接理解字符串的意思需要将其解析成内部格式才行。条件表达式的解析过程始于 ConditionRouter 的构造方法下面一起看一下
public ConditionRouter(URL url) {this.url url;// 获取 priority 和 force 配置this.priority url.getParameter(Constants.PRIORITY_KEY, 0);this.force url.getParameter(Constants.FORCE_KEY, false);try {// 获取路由规则String rule url.getParameterAndDecoded(Constants.RULE_KEY);if (rule null || rule.trim().length() 0) {throw new IllegalArgumentException(Illegal route rule!);}rule rule.replace(consumer., ).replace(provider., );// 定位 分隔符int i rule.indexOf();// 分别获取服务消费者和提供者匹配规则String whenRule i 0 ? null : rule.substring(0, i).trim();String thenRule i 0 ? rule.trim() : rule.substring(i 2).trim();// 解析服务消费者匹配规则MapString, MatchPair when StringUtils.isBlank(whenRule) || true.equals(whenRule) ? new HashMapString, MatchPair() : parseRule(whenRule);// 解析服务提供者匹配规则MapString, MatchPair then StringUtils.isBlank(thenRule) || false.equals(thenRule) ? null : parseRule(thenRule);this.whenCondition when;this.thenCondition then;} catch (ParseException e) {throw new IllegalStateException(e.getMessage(), e);}
}
如上ConditionRouter 构造方法先是对路由规则做预处理然后调用 parseRule 方法分别对服务提供者和消费者规则进行解析最后将解析结果赋值给 whenCondition 和 thenCondition 成员变量。ConditionRouter 构造方法不是很复杂这里就不多说了。下面我们把重点放在 parseRule 方法上在详细介绍这个方法之前我们先来看一个内部类。
private static final class MatchPair {final SetString matches new HashSetString();final SetString mismatches new HashSetString();
}
MatchPair 内部包含了两个 Set 型的成员变量分别用于存放匹配和不匹配的条件。这个类两个成员变量会在 parseRule 方法中被用到下面来看一下。
private static MapString, MatchPair parseRule(String rule)throws ParseException {// 定义条件映射集合MapString, MatchPair condition new HashMapString, MatchPair();if (StringUtils.isBlank(rule)) {return condition;}MatchPair pair null;SetString values null;// 通过正则表达式匹配路由规则ROUTE_PATTERN ([!,]*)\s*([^!,\s])// 这个表达式看起来不是很好理解第一个括号内的表达式用于匹配, !, 和 , 等符号。// 第二括号内的用于匹配英文字母数字等字符。举个例子说明一下// host 2.2.2.2 host ! 1.1.1.1 method hello// 匹配结果如下// 括号一 括号二// 1. null host// 2. 2.2.2.2// 3. host// 4. ! 1.1.1.1 // 5. method// 6. hellofinal Matcher matcher ROUTE_PATTERN.matcher(rule);while (matcher.find()) {// 获取括号一内的匹配结果String separator matcher.group(1);// 获取括号二内的匹配结果String content matcher.group(2);// 分隔符为空表示匹配的是表达式的开始部分if (separator null || separator.length() 0) {// 创建 MatchPair 对象pair new MatchPair();// 存储 匹配项, MatchPair 键值对比如 host, MatchPaircondition.put(content, pair); } // 如果分隔符为 表明接下来也是一个条件else if (.equals(separator)) {// 尝试从 condition 获取 MatchPairif (condition.get(content) null) {// 未获取到 MatchPair重新创建一个并放入 condition 中pair new MatchPair();condition.put(content, pair);} else {pair condition.get(content);}} // 分隔符为 else if (.equals(separator)) {if (pair null)throw new ParseException(Illegal route rule ...);values pair.matches;// 将 content 存入到 MatchPair 的 matches 集合中values.add(content);} // 分隔符为 ! else if (!.equals(separator)) {if (pair null)throw new ParseException(Illegal route rule ...);values pair.mismatches;// 将 content 存入到 MatchPair 的 mismatches 集合中values.add(content);}// 分隔符为 ,else if (,.equals(separator)) {if (values null || values.isEmpty())throw new ParseException(Illegal route rule ...);// 将 content 存入到上一步获取到的 values 中可能是 matches也可能是 mismatchesvalues.add(content);} else {throw new ParseException(Illegal route rule ...);}}return condition;
}
以上就是路由规则的解析逻辑该逻辑由正则表达式 一个 while 循环 数个条件分支组成。下面使用一个示例对解析逻辑进行演绎。示例为 host 2.2.2.2 host ! 1.1.1.1 method hello。正则解析结果如下 括号一 括号二
1. null host
2. 2.2.2.2
3. host
4. ! 1.1.1.1
5. method
6. hello
现在线程进入 while 循环
第一次循环分隔符 separator nullcontent “host”。此时创建 MatchPair 对象并存入到 condition 中condition {“host”: MatchPair123}
第二次循环分隔符 separator “”content “2.2.2.2”pair MatchPair123。此时将 2.2.2.2 放入到 MatchPair123 对象的 matches 集合中。
第三次循环分隔符 separator “”content “host”。host 已存在于 condition 中因此 pair MatchPair123。
第四次循环分隔符 separator “!”content “1.1.1.1”pair MatchPair123。此时将 1.1.1.1 放入到 MatchPair123 对象的 mismatches 集合中。
第五次循环分隔符 separator “”content “method”。condition.get(“method”) null因此新建一个 MatchPair 对象并放入到 condition 中。此时 condition {“host”: MatchPair123, “method”: MatchPair 456}
第六次循环分隔符 separator “”content “2.2.2.2”pair MatchPair456。此时将 hello 放入到 MatchPair456 对象的 matches 集合中。
循环结束此时 condition 的内容如下