99精品伊人亚洲|最近国产中文炮友|九草在线视频支援|AV网站大全最新|美女黄片免费观看|国产精品资源视频|精彩无码视频一区|91大神在线后入|伊人终合在线播放|久草综合久久中文

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Dubbo通過RouterFactory接口實現(xiàn)路由機制服務

電子設計 ? 來源:博客園 ? 作者:佚名 ? 2020-04-16 07:43 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

Dubbo路由機制是在服務間的調用時,通過將服務提供者按照設定的路由規(guī)則來決定調用哪一個具體的服務。

路由服務結構

Dubbo實現(xiàn)路由都是通過實現(xiàn)RouterFactory接口。當前版本 dubbo-2.7.5 實現(xiàn)該接口類如下:

路由實現(xiàn)工廠類是在 router 包下

由于 RouterFactory 是 SPI 接口,同時在獲取路由 RouterFactory#getRouter 方法上有 @Adaptive(“protocol”) 注解,所以在獲取路由的時候會動態(tài)調用需要的工廠類。

可以看到 getRouter 方法返回的是一個 Router 接口,該接口信息如下

其中 Router#route 是服務路由的入口,對于不同類型的路由工廠,有特定的 Router 實現(xiàn)類。

以上就是通過解析 URL,獲取到具體的 Router,通過調用 Router#router 過濾出符合當前路由規(guī)則的 invokers。

服務路由實現(xiàn)

上面展示了路由實現(xiàn)類,這幾個實現(xiàn)類型中,ConditionRouter 條件路由是最為常用的類型,由于文章篇幅有限,本文就不對全部的路由類型逐一分析,只對條件路由進行具體分析,只要弄懂這一個類型,其它類型的解析就能容易掌握。

條件路由參數(shù)規(guī)則

在分析條件路由前,先了解條件路由的參數(shù)配置,官方文檔如下:

條件路由規(guī)則內容如下:

條件路由實現(xiàn)分析

分析路由實現(xiàn),主要分析工廠類的 xxxRouterFactory#getRouter 和 xxxRouter#route 方法。

ConditionRouterFactory#getRouter

ConditionRouterFactory 中通過創(chuàng)建 ConditionRouter 對象來初始化解析相關參數(shù)配置。

在 ConditionRouter 構造函數(shù)中,從 URL 里獲取 rule 的字符串格式的規(guī)則,解析規(guī)則在 ConditionRouter#init 初始化方法中。

public void init(String rule) {

try {

if (rule == null || rule.trim().length() == 0) {

throw new IllegalArgumentException(“Illegal route rule!”);

}

// 去掉 consumer. 和 provider. 的標識

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();

// 解析消費者路由規(guī)則

Map《String, MatchPair》 when = StringUtils.isBlank(whenRule) || “true”.equals(whenRule) ? new HashMap《String, MatchPair》() : parseRule(whenRule);

// 解析提供者路由規(guī)則

Map《String, MatchPair》 then = StringUtils.isBlank(thenRule) || “false”.equals(thenRule) ? null : parseRule(thenRule);

// NOTE: It should be determined on the business level whether the `When condition` can be empty or not.

this.whenCondition = when;

this.thenCondition = then;

} catch (ParseException e) {

throw new IllegalStateException(e.getMessage(), e);

}

}

以路由規(guī)則字符串中的=》為分隔符,將消費者匹配條件和提供者匹配條件分割,解析兩個路由規(guī)則后,賦值給當前對象的變量。

調用 parseRule 方法來解析消費者和服務者路由規(guī)則。

// 正則驗證路由規(guī)則

protected static final Pattern ROUTE_PATTERN = Pattern.compile(“([&!=,]*)\s*([^&!=,\s]+)”);

private static Map《String, MatchPair》 parseRule(String rule)

throws ParseException {

/**

* 條件變量和條件變量值的映射關系

* 比如 host =》 127.0.0.1 則保存著 host 和 127.0.0.1 的映射關系

*/

Map《String, MatchPair》 condition = new HashMap《String, MatchPair》();

if (StringUtils.isBlank(rule)) {

return condition;

}

// Key-Value pair, stores both match and mismatch conditions

MatchPair pair = null;

// Multiple values

Set《String》 values = null;

final Matcher matcher = ROUTE_PATTERN.matcher(rule);

while (matcher.find()) {

// 獲取正則前部分匹配(第一個括號)的內容

String separator = matcher.group(1);

// 獲取正則后部分匹配(第二個括號)的內容

String content = matcher.group(2);

// 如果獲取前部分為空,則表示規(guī)則開始位置,則當前 content 必為條件變量

if (StringUtils.isEmpty(separator)) {

pair = new MatchPair();

condition.put(content, pair);

}

// 如果分隔符是 &,則 content 為條件變量

else if (“&”.equals(separator)) {

// 當前 content 是條件變量,用來做映射集合的 key 的,如果沒有則添加一個元素

if (condition.get(content) == null) {

pair = new MatchPair();

condition.put(content, pair);

} else {

pair = condition.get(content);

}

}

// 如果當前分割符是 = ,則當前 content 為條件變量值

else if (“=”.equals(separator)) {

if (pair == null) {

throw new ParseException(“Illegal route rule ”“

+ rule + ”“, The error char ‘” + separator

+ “’ at index ” + matcher.start() + “ before ”“

+ content + ”“。”, matcher.start());

}

// 由于 pair 還沒有被重新初始化,所以還是上一個條件變量的對象,所以可以將當前條件變量值在引用對象上賦值

values = pair.matches;

values.add(content);

}

// 如果當前分割符是 = ,則當前 content 也是條件變量值

else if (“!=”.equals(separator)) {

if (pair == null) {

throw new ParseException(“Illegal route rule ”“

+ rule + ”“, The error char ‘” + separator

+ “’ at index ” + matcher.start() + “ before ”“

+ content + ”“?!?, matcher.start());

}

// 與 = 時同理

values = pair.mismatches;

values.add(content);

}

// 如果當前分割符為 ‘,’,則當前 content 也為條件變量值

else if (“,”.equals(separator)) { // Should be separated by ‘,’

if (values == null || values.isEmpty()) {

throw new ParseException(“Illegal route rule ”“

+ rule + ”“, The error char ‘” + separator

+ “’ at index ” + matcher.start() + “ before ”“

+ content + ”“?!?, matcher.start());

}

// 直接向條件變量值集合中添加數(shù)據

values.add(content);

} else {

throw new ParseException(“Illegal route rule ”“ + rule

+ ”“, The error char ‘” + separator + “’ at index ”

+ matcher.start() + “ before ”“ + content + ”“?!保?matcher.start());

}

}

return condition;

}

上面就是解析條件路由規(guī)則的過程,條件變量的值都保存在 MatchPair 中的 matches、mismatches 屬性中,=和,的條件變量值放在可以匹配的 matches 中,!=的條件變量值放在不可匹配路由規(guī)則的 mismatches 中。賦值過程中,代碼還是比較優(yōu)雅。

實際上 matches、mismatches 就是保存的是條件變量值。

ConditionRouter#route

Router#route的作用就是匹配出符合路由規(guī)則的 Invoker 集合。

// 在初始化中進行被復制的變量

// 消費者條件匹配規(guī)則

protected Map《String, MatchPair》 whenCondition;

// 提供者條件匹配規(guī)則

protected Map《String, MatchPair》 thenCondition;

public 《T》 List《Invoker《T》》 route(List《Invoker《T》》 invokers, URL url, Invocation invocation)

throws RpcException {

if (!enabled) {

return invokers;

}

// 驗證 invokers 是否為空

if (CollectionUtils.isEmpty(invokers)) {

return invokers;

}

try {

// 校驗消費者是否有規(guī)則匹配,如果沒有則返回傳入的 Invoker

if (!matchWhen(url, invocation)) {

return invokers;

}

List《Invoker《T》》 result = new ArrayList《Invoker《T》》();

if (thenCondition == null) {

logger.warn(“The current consumer in the service blacklist. consumer: ” + NetUtils.getLocalHost() + “, service: ” + url.getServiceKey());

return result;

}

// 遍歷傳入的 invokers,匹配提供者是否有規(guī)則匹配

for (Invoker《T》 invoker : invokers) {

if (matchThen(invoker.getUrl(), url)) {

result.add(invoker);

}

}

// 如果 result 不為空,或當前對象 force=true 則返回 result 的 Invoker 列表

if (!result.isEmpty()) {

return result;

} else if (force) {

logger.warn(“The route result is empty and force execute. consumer: ” + NetUtils.getLocalHost() + “, service: ” + url.getServiceKey() + “, router: ” + url.getParameterAndDecoded(RULE_KEY));

return result;

}

} catch (Throwable t) {

logger.error(“Failed to execute condition router rule: ” + getUrl() + “, invokers: ” + invokers + “, cause: ” + t.getMessage(), t);

}

return invokers;

}

上面代碼可以看到,只要消費者沒有匹配的規(guī)則或提供者沒有匹配的規(guī)則及 force=false 時,不會返回傳入的參數(shù)的 Invoker。

匹配消費者路由規(guī)則和提供者路由規(guī)則方法是 matchWhen 和 matchThen

這兩個匹配方法都是調用同一個方法 matchCondition 實現(xiàn)的。將消費者或提供者 URL 轉為 Map,然后與 whenCondition 或 thenCondition 進行匹配。

匹配過程中,如果 key (即 sampleValue 值)存在對應的值,則通過 MatchPair#isMatch 方法再進行匹配。

private boolean isMatch(String value, URL param) {

// 存在可匹配的規(guī)則,不存在不可匹配的規(guī)則

if (!matches.isEmpty() && mismatches.isEmpty()) {

// 不可匹配的規(guī)則列表為空時,只要可匹配的規(guī)則匹配上,直接返回 true

for (String match : matches) {

if (UrlUtils.isMatchGlobPattern(match, value, param)) {

return true;

}

}

return false;

}

// 存在不可匹配的規(guī)則,不存在可匹配的規(guī)則

if (!mismatches.isEmpty() && matches.isEmpty()) {

// 不可匹配的規(guī)則列表中存在,則返回false

for (String mismatch : mismatches) {

if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) {

return false;

}

}

return true;

}

// 存在可匹配的規(guī)則,也存在不可匹配的規(guī)則

if (!matches.isEmpty() && !mismatches.isEmpty()) {

// 都不為空時,不可匹配的規(guī)則列表中存在,則返回 false

for (String mismatch : mismatches) {

if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) {

return false;

}

}

for (String match : matches) {

if (UrlUtils.isMatchGlobPattern(match, value, param)) {

return true;

}

}

return false;

}

// 最后剩下的是 可匹配規(guī)則和不可匹配規(guī)則都為空時

return false;

}

匹配過程再調用 UrlUtils#isMatchGlobPattern 實現(xiàn)

public static boolean isMatchGlobPattern(String pattern, String value, URL param) {

// 如果以 $ 開頭,則獲取 URL 中對應的值

if (param != null && pattern.startsWith(“$”)) {

pattern = param.getRawParameter(pattern.substring(1));

}

//

return isMatchGlobPattern(pattern, value);

}

public static boolean isMatchGlobPattern(String pattern, String value) {

if (“*”.equals(pattern)) {

return true;

}

if (StringUtils.isEmpty(pattern) && StringUtils.isEmpty(value)) {

return true;

}

if (StringUtils.isEmpty(pattern) || StringUtils.isEmpty(value)) {

return false;

}

// 獲取通配符位置

int i = pattern.lastIndexOf(‘*’);

// 如果value中沒有 “*” 通配符,則整個字符串值匹配

if (i == -1) {

return value.equals(pattern);

}

// 如果 “*” 在最后面,則匹配字符串 “*” 之前的字符串即可

else if (i == pattern.length() - 1) {

return value.startsWith(pattern.substring(0, i));

}

// 如果 “*” 在最前面,則匹配字符串 “*” 之后的字符串即可

else if (i == 0) {

return value.endsWith(pattern.substring(i + 1));

}

// 如果 “*” 不在字符串兩端,則同時匹配字符串 “*” 左右兩邊的字符串

else {

String prefix = pattern.substring(0, i);

String suffix = pattern.substring(i + 1);

return value.startsWith(prefix) && value.endsWith(suffix);

}

}

就這樣完成全部的條件路由規(guī)則匹配,雖然看似代碼較為繁雜,但是理清規(guī)則、思路,一步一步還是較好解析,前提是要熟悉相關參數(shù)的用法及形式,不然代碼較難理解。

最后

單純從邏輯上,如果能夠掌握條件路由的實現(xiàn),去研究其它方式的路由實現(xiàn),相信不會有太大問題。只是例如像腳本路由的實現(xiàn),你得先會使用腳本執(zhí)行引擎為前提,不然就不理解它的代碼。最后,在 dubbo-admin 上可以設置路由,大家可以嘗試各種使用規(guī)則,通過實操才能更好掌握和理解路由機制的實現(xiàn)。

責任編輯:gt


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 接口
    +關注

    關注

    33

    文章

    9005

    瀏覽量

    153783
  • 路由
    +關注

    關注

    0

    文章

    280

    瀏覽量

    42492
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    聊聊Dubbo - Dubbo可擴展機制實戰(zhàn)

    的做到了上面兩點。這要得益于Dubbo的微內核+插件的機制。接下來的章節(jié)中我們會慢慢揭開Dubbo擴展機制的神秘面紗。2. 可擴展的幾種解決方案通常可擴展的
    發(fā)表于 06-04 17:33

    聊聊Dubbo - Dubbo可擴展機制源碼解析

    摘要: 在Dubbo可擴展機制實戰(zhàn)中,我們了解了Dubbo擴展機制的一些概念,初探了Dubbo中LoadBalance的
    發(fā)表于 06-05 18:43

    Dubbo開源現(xiàn)狀與未來規(guī)劃

    循環(huán)依賴和反向依賴的出現(xiàn)。Dubbo 還有一個很重要的設計哲學就是平等對待第三方的擴展,即 Dubbo 內建的功能也是通過同樣的擴展機制提供出來的,第三方的擴展和內建功能可以相互取代。
    發(fā)表于 07-05 15:21

    攜程的 Dubbo 之路

    用戶自行擴展,我們在PB序列化器的實現(xiàn)上增加了擴展接口,允許用戶在外圍繼續(xù)增加數(shù)據壓縮的功能。整體序列化器的實現(xiàn)并不是很難,倒是有一點需要注意的是,由于 Dubbo
    發(fā)表于 10-12 15:05

    基于FPGA的VGA接口實現(xiàn)和字符顯示

    基于FPGA的VGA接口實現(xiàn)和字符顯示論文
    發(fā)表于 10-29 17:18 ?8次下載

    如何通過STM32的串口實現(xiàn)簡易脫機編程器

    如何通過STM32的串口實現(xiàn)簡易脫機編程器如何通過STM32的串口實現(xiàn)簡易脫機編程器如何通過STM32的串
    發(fā)表于 04-25 09:38 ?60次下載

    Dubbo源代碼實現(xiàn)服務調用的動態(tài)代理和負載均衡

    我們知道,Dubbo服務調用封裝成普通的Spring的Bean,于是我們可以像使用本地的Spring Bean一樣,來調用遠端的Dubbo服務,并有LoadBalance和Failo
    發(fā)表于 03-12 14:35 ?0次下載

    多態(tài)路由機制研究

    如何基于有限且確定的路由結構來支持多樣化服務是當前研究面臨的問題,采用路由結構的自組織和自調節(jié)來實現(xiàn)路由與業(yè)務的自適配,提出一種面向多樣化
    發(fā)表于 03-13 16:43 ?2次下載
    多態(tài)<b class='flag-5'>路由</b><b class='flag-5'>機制</b>研究

    服務化改造實踐(一)| Dubbo + ZooKeeper

    ?GreetingService?{String?sayHello(String?name);}2、服務端:服務實現(xiàn)實現(xiàn) ?GreetingService接口,并通過 @Service
    發(fā)表于 08-27 16:36 ?319次閱讀
    <b class='flag-5'>服務</b>化改造實踐(一)| <b class='flag-5'>Dubbo</b> + ZooKeeper

    服務化改造實踐(一)| Dubbo + ZooKeeper

    GreetingService接口,并通過 @Service 來標注其為Dubbo的一個服務。@Servicepublic?class?AnnotatedGreetingServic
    發(fā)表于 08-27 17:25 ?395次閱讀
    <b class='flag-5'>服務</b>化改造實踐(一)| <b class='flag-5'>Dubbo</b> + ZooKeeper

    dubbo-go 中的 TPS Limit 設計與實現(xiàn)

    限流,比如說限制一分鐘內某個接口只能訪問 200 次,超過這個次數(shù),則會被拒絕服務。在 Dubbo 的 Java 版本上,只有一個實現(xiàn),就是 DefaultTPSLimiter 。 D
    發(fā)表于 03-17 15:27 ?760次閱讀

    Dubbo 如何成為連接異構微服務體系的最佳服務開發(fā)框架

    從編程開發(fā)的角度來說,Apache Dubbo (以下簡稱 Dubbo )首先是一款 RPC 服務框架,它最大的優(yōu)勢在于提供了面向接口代理的服務
    發(fā)表于 03-12 17:04 ?1093次閱讀
    <b class='flag-5'>Dubbo</b> 如何成為連接異構微<b class='flag-5'>服務</b>體系的最佳<b class='flag-5'>服務</b>開發(fā)框架

    ARM與FPGA的接口實現(xiàn)的解析

    ARM與FPGA的接口實現(xiàn)的解析(應廣單片機)-該文檔為ARM與FPGA的接口實現(xiàn)的解析詳述資料,講解的還不錯,感興趣的可以下載看看…………………………
    發(fā)表于 07-22 09:47 ?14次下載
    ARM與FPGA的<b class='flag-5'>接口實現(xiàn)</b>的解析

    C#-Interface接口實現(xiàn)

    C#-Interface接口實現(xiàn)(安徽理士電源技術有限公司招聘信息)-該文檔為C#-Interface接口實現(xiàn)講解文檔,是一份還算不錯的參考文檔,感興趣的可以下載看看,,,,,,,,,,,,,,,,,,
    發(fā)表于 09-28 09:42 ?3次下載
    C#-Interface<b class='flag-5'>接口實現(xiàn)</b>

    通過標準的CAN接口實現(xiàn)的測試臺自動化解決方案

    通過標準的CAN接口實現(xiàn)的測試臺自動化解決方案
    的頭像 發(fā)表于 10-11 14:17 ?2252次閱讀