上一節咱們主要講解了利用dubbo-admin如何進行參數的動態修改,本節將重點介紹集羣實現中另一個實現細節:路由機制,Dubbo的路由機制主要解決的目的就是服務調用時,從已知的全部服務提供者中根據路由規則刷選服務提供者。架構
如下內容來源於官方文檔: 併發
以上是Dubbo 路由機制的基本知識,接下來從源碼的角度分析一下其實現原理。分佈式
能夠經過dubbo-admin管理後臺,動態添加路由規則,其界面如圖所示: 高併發
點擊保存後,使用URL描述一條路由規則,並將存儲在註冊中心${service}/routers目錄下,而後通知相關訂閱者(服務消費者【調用方】)。 具體調用的方法爲RegistryDirecotry#notify方法,其片斷以下:源碼分析
// routers if (routerUrls != null && !routerUrls.isEmpty()) { // @1 List<router> routers = toRouters(routerUrls); // @2 if (routers != null) { // null - do nothing setRouters(routers); // @3 } }
代碼@1:若是routerUrls 不爲空,說明註冊中心的catalog=routers目錄下新增或刪除了某些路由規則,最後存在路由規則。 代碼@2:將路由規則URL轉換爲路由實現類Router接口的實現類,例如條件路由規則、腳本路由規則具體實現類。 代碼@3:將現存的路由規則實現類覆蓋RegistroyDirectory#routers屬性,在下一次服務調用時,這些路由規則將生效。this
咱們見到看一下toRouter方法的實現:url
RegistryDirectory#toRouters.net
private List<router> toRouters(List<url> urls) { List<router> routers = new ArrayList<router>(); if (urls == null || urls.isEmpty()) { return routers; } if (urls != null && !urls.isEmpty()) { for (URL url : urls) { if (Constants.EMPTY_PROTOCOL.equals(url.getProtocol())) { continue; } String routerType = url.getParameter(Constants.ROUTER_KEY); if (routerType != null && routerType.length() > 0) { url = url.setProtocol(routerType); } try { Router router = routerFactory.getRouter(url); if (!routers.contains(router)) routers.add(router); } catch (Throwable t) { logger.error("convert router url to router error, url: " + url, t); } } } return routers; }
方法實現比較簡單,就是基於協議頭condition://或script://構建具體的路由規則實現類。 從上面兩個方法能夠看出,當主從中心的路由配置發生變化後,會從新構建RegistryDirectory的List< Router> routers屬性,那這個屬性在何時用呢?3d
AbstractDirectory#listcode
public List<invoker<t>> list(Invocation invocation) throws RpcException { if (destroyed) { throw new RpcException("Directory already destroyed .url: " + getUrl()); } List<invoker<t>> invokers = doList(invocation); List<router> localRouters = this.routers; // local reference if (localRouters != null && !localRouters.isEmpty()) { for (Router router : localRouters) { try { if (router.getUrl() == null || router.getUrl().getParameter(Constants.RUNTIME_KEY, false)) { invokers = router.route(invokers, getConsumerUrl(), invocation); } } catch (Throwable t) { logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t); } } } return invokers; }
在經過RegistryDirector時,獲取List< Invoker>時,會對全部的Invoker列表進行路由過濾,而後返回符合路由規則的Invoker,本文就不相信分析Dubbo是如何根據配置的條件路由規則、腳本路由規則去過濾,其實現細節,若有興趣,可關注:ConditionRouter、ScriptRouter。
做者介紹:丁威,《RocketMQ技術內幕》做者,RocketMQ 社區佈道師,公衆號:中間件興趣圈 維護者,目前已陸續發表源碼分析Java集合、Java 併發包(JUC)、Netty、Mycat、Dubbo、RocketMQ、Mybatis等源碼專欄。能夠點擊連接:中間件知識星球,一塊兒探討高併發、分佈式服務架構,交流源碼。
</router></invoker<t></invoker<t></router></router></url></router></router>