亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

dubbo源碼解析——Directory

neu / 1470人閱讀

摘要:首先來看一下接口的實現(xiàn)類他主要有兩個實現(xiàn)類一個是一個是,本文主要解析。如果傳入的列表為空,則意味著該規(guī)則僅是重寫規(guī)則或路由規(guī)則,需要對其進行重新對比以決定是否重新引用。

首先來看一下directory接口的實現(xiàn)類,他主要有兩個實現(xiàn)類,一個是StaticDirectory,一個是RegistryDirectory,本文主要解析RegistryDirectory。

StaticDirectory
StaticDirectory中的Static關(guān)鍵詞來看,就知道,這個其實是不會動態(tài)變化的,從下圖知道,他的Invoker是通過構(gòu)造函數(shù)傳入,StaticDirectory用得比較少,主要用在服務(wù)對多注冊中心的引用

RegistryDirectory
首先看下它的結(jié)構(gòu):

這個NotifyListener中的notify方法就是注冊中心的回調(diào),也就是它之所以能根據(jù)注冊中心動態(tài)變化的根源所在.

上文中,Directory的doList方法,這是一個抽象方法,通過調(diào)用子類RegistryDirectory的doList方法,從Directory中選擇出invoker列表。

@Override
    public List> doList(Invocation invocation) {
        if (forbidden) {
            // 如果forbidden為true,則沒有服務(wù)提供者  或者  服務(wù)提供者不可用
            throw new RpcException(RpcException.FORBIDDEN_EXCEPTION,
                "No provider available from registry " + getUrl().getAddress() + " for service " + getConsumerUrl().getServiceKey() + " on consumer " +  NetUtils.getLocalHost()
                        + " use dubbo version " + Version.getVersion() + ", please check status of providers(disabled, not registered or in blacklist).");
        }
        List> invokers = null;
        Map>> localMethodInvokerMap = this.methodInvokerMap;
        if (localMethodInvokerMap != null && localMethodInvokerMap.size() > 0) {
            // 獲取方法名稱
            String methodName = RpcUtils.getMethodName(invocation);
            // 獲取方法參數(shù)
            Object[] args = RpcUtils.getArguments(invocation);
            if (args != null && args.length > 0 && args[0] != null
                    && (args[0] instanceof String || args[0].getClass().isEnum())) {
                // 如果第一個參數(shù)是字符串類型 或者 枚舉類型
                // 可以根據(jù)第一個參數(shù)枚舉路由
                invokers = localMethodInvokerMap.get(methodName + "." + args[0]);
            }
            if (invokers == null) {
                // 仍然為null,使用方法名稱獲取
                invokers = localMethodInvokerMap.get(methodName);
            }
            if (invokers == null) {
                // 仍讓為null,使用 * 隨機取一個invoker來實現(xiàn)調(diào)用
                invokers = localMethodInvokerMap.get(Constants.ANY_VALUE);
            }
            if (invokers == null) {
                // 仍然為null,使用迭代器獲取一個invoker
                Iterator>> iterator = localMethodInvokerMap.values().iterator();
                if (iterator.hasNext()) {
                    invokers = iterator.next();
                }
            }
        }
        return invokers == null ? new ArrayList>(0) : invokers;
    }

從中可以看出,Directory獲取invoker是從methodInvokerMap中獲取的。invoker什么時候?qū)懭氲紻irectory的methodInvokerMap里面呢?就是在回調(diào)方法notify的時候操作的。

@Override
    public synchronized void notify(List urls) {
        // 聲明invoker的URL引用數(shù)組
        List invokerUrls = new ArrayList();

        // 聲明router的URL引用數(shù)組
        List routerUrls = new ArrayList();

        // 聲明configurator(配置器)的URL引用數(shù)組
        List configuratorUrls = new ArrayList();

        for (URL url : urls) {
            // 獲取協(xié)議名稱
            String protocol = url.getProtocol();
            // 獲取分類
            String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
            
            if (Constants.ROUTERS_CATEGORY.equals(category)
                    || Constants.ROUTE_PROTOCOL.equals(protocol)) {
                // 如果是路由分類 或者  路由協(xié)議
                routerUrls.add(url);
            } else if (Constants.CONFIGURATORS_CATEGORY.equals(category)
                    || Constants.OVERRIDE_PROTOCOL.equals(protocol)) {
                // 如果是配置器分類 或者 重寫協(xié)議
                configuratorUrls.add(url);
            } else if (Constants.PROVIDERS_CATEGORY.equals(category)) {
                // 如果是提供方分類
                invokerUrls.add(url);
            } else {
                logger.warn("Unsupported category " + category + " in notified url: " + url + " from registry " + getUrl().getAddress() + " to consumer " + NetUtils.getLocalHost());
            }
        }
        // 通過url獲取configurators
        if (configuratorUrls != null && !configuratorUrls.isEmpty()) {
            this.configurators = toConfigurators(configuratorUrls);
        }
        // 通過url獲取routers
        if (routerUrls != null && !routerUrls.isEmpty()) {
            List routers = toRouters(routerUrls);
            if (routers != null) { // null - do nothing
                setRouters(routers);
            }
        }
        List localConfigurators = this.configurators;
        // 合并override參數(shù)
        this.overrideDirectoryUrl = directoryUrl;
        if (localConfigurators != null && !localConfigurators.isEmpty()) {
            for (Configurator configurator : localConfigurators) {
                this.overrideDirectoryUrl = configurator.configure(overrideDirectoryUrl);
            }
        }
        // 刷新providers
        refreshInvoker(invokerUrls);
    }

/**
     * 把invokerUrl列表 轉(zhuǎn)化成 invoker Map。轉(zhuǎn)換規(guī)則如下
     * 1.如果URL已經(jīng)轉(zhuǎn)換為invoker,則不再重新引用它,并且直接從緩存中獲得它,并且注意URL中的任何參數(shù)更改都將被重新引用。
     * 2.如果傳入的invoker列表不是空的,則意味著它是最新的調(diào)用列表。
     * 3.如果傳入的invokerUrl列表為空,則意味著該規(guī)則僅是重寫規(guī)則或路由規(guī)則,需要對其進行重新對比以決定是否重新引用。
     * @param invokerUrls this parameter can"t be null
     */
    private void refreshInvoker(List invokerUrls) {
        if (invokerUrls != null && invokerUrls.size() == 1 && invokerUrls.get(0) != null
                && Constants.EMPTY_PROTOCOL.equals(invokerUrls.get(0).getProtocol())) {
            // 只有一個invoker url,并且協(xié)議是空協(xié)議

            // 設(shè)置禁止訪問
            this.forbidden = true;
            // 設(shè)置methodInvokerMap為null
            this.methodInvokerMap = null;
            // 關(guān)閉所有invoker
            destroyAllInvokers();

        } else {
            // 設(shè)置允許訪問
            this.forbidden = false;

            Map> oldUrlInvokerMap = this.urlInvokerMap;

            if (invokerUrls.isEmpty() && this.cachedInvokerUrls != null) {
                // 如果傳入的invoker url是空的,從緩存中添加
                invokerUrls.addAll(this.cachedInvokerUrls);
            } else {
                // 緩存invoker url,便于比較
                this.cachedInvokerUrls = new HashSet();
                this.cachedInvokerUrls.addAll(invokerUrls);
            }
            if (invokerUrls.isEmpty()) {
                return;
            }
            // 把invoker url列表 轉(zhuǎn)換成 key為url,value為invoker的Map
            Map> newUrlInvokerMap = toInvokers(invokerUrls);
            // 把invoker url列表 轉(zhuǎn)換成 key為method,value為invoker的Map
            Map>> newMethodInvokerMap = toMethodInvokers(newUrlInvokerMap);

            if (newUrlInvokerMap == null || newUrlInvokerMap.size() == 0) {
                logger.error(new IllegalStateException("urls to invokers error .invokerUrls.size :" + invokerUrls.size() + ", invoker.size :0. urls :" + invokerUrls.toString()));
                return;
            }
            // 如果有多個分組,就合并methodInvokerMap
            this.methodInvokerMap = multiGroup ? toMergeMethodInvokerMap(newMethodInvokerMap) : newMethodInvokerMap;
            this.urlInvokerMap = newUrlInvokerMap;
            try {
                // 關(guān)閉沒有使用invoker
                destroyUnusedInvokers(oldUrlInvokerMap, newUrlInvokerMap);
            } catch (Exception e) {
                logger.warn("destroyUnusedInvokers error. ", e);
            }
        }
    }

也就是注冊中心有變化,則更新methodInvokerMap和urlInvokerMap的值(這個后面講服務(wù)引用原理的時候會再提一下),這就是官網(wǎng)提到的它的值可能是動態(tài)變化的,比如注冊中心推送變更的原因所在

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/72099.html

相關(guān)文章

  • dubbo源碼解析——消費過程

    摘要:上一篇源碼解析概要篇中我們了解到中的一些概念及消費端總體調(diào)用過程。由于在生成代理實例的時候,在構(gòu)造函數(shù)中賦值了,因此可以只用該進行方法的調(diào)用。 上一篇 dubbo源碼解析——概要篇中我們了解到dubbo中的一些概念及消費端總體調(diào)用過程。本文中,將進入消費端源碼解析(具體邏輯會放到代碼的注釋中)。本文先是對消費過程的總體代碼邏輯理一遍,個別需要細講的點,后面會專門的文章進行解析。...

    darkbug 評論0 收藏0
  • dubbo源碼解析(四)注冊中心——dubbo

    摘要:一該類繼承了類,該類里面封裝了一個重連機制,而注冊中心核心的功能注冊訂閱取消注冊取消訂閱,查詢注冊列表都是調(diào)用了我上一篇文章源碼解析三注冊中心開篇中講到的實現(xiàn)方法,畢竟這種實現(xiàn)注冊中心的方式是默認的方式,不過推薦使用,這個后續(xù)講解。 注冊中心——dubbo 目標(biāo):解釋以為dubbo實現(xiàn)的注冊中心原理,解讀duubo-registry-default源碼 dubbo內(nèi)置的注冊中心實現(xiàn)方式...

    andot 評論0 收藏0
  • dubbo源碼解析——概要篇

    摘要:服務(wù)提供者代碼上面這個類會被封裝成為一個實例,并新生成一個實例。這樣當(dāng)網(wǎng)絡(luò)通訊層收到一個請求后,會找到對應(yīng)的實例,并調(diào)用它所對應(yīng)的實例,從而真正調(diào)用了服務(wù)提供者的代碼。 這次源碼解析借鑒《肥朝》前輩的dubbo源碼解析,進行源碼學(xué)習(xí)??偨Y(jié)起來就是先總體,后局部.也就是先把需要注意的概念先拋出來,把整體架構(gòu)圖先畫出來.讓讀者拿著地圖跟著我的腳步,并且每一步我都提醒,現(xiàn)在我們在哪,我們下一...

    Meathill 評論0 收藏0
  • dubbo源碼解析(四十五)服務(wù)引用過程

    摘要:服務(wù)引用過程目標(biāo)從源碼的角度分析服務(wù)引用過程。并保留服務(wù)提供者的部分配置,比如版本,,時間戳等最后將合并后的配置設(shè)置為查詢字符串中。的可以參考源碼解析二十三遠程調(diào)用的一的源碼分析。 dubbo服務(wù)引用過程 目標(biāo):從源碼的角度分析服務(wù)引用過程。 前言 前面服務(wù)暴露過程的文章講解到,服務(wù)引用有兩種方式,一種就是直連,也就是直接指定服務(wù)的地址來進行引用,這種方式更多的時候被用來做服務(wù)測試,不...

    xiaowugui666 評論0 收藏0
  • dubbo之SPI

    摘要:簡介全稱為,是一種服務(wù)發(fā)現(xiàn)機制。的本質(zhì)是將接口實現(xiàn)類的全限定名配置在文件中,并由服務(wù)加載器讀取配置文件,加載實現(xiàn)類。不過,并未使用原生的機制,而是對其進行了增強,使其能夠更好的滿足需求。并未使用,而是重新實現(xiàn)了一套功能更強的機制。 1、SPI簡介 SPI 全稱為 Service Provider Interface,是一種服務(wù)發(fā)現(xiàn)機制。SPI 的本質(zhì)是將接口實現(xiàn)類的全限定名配置在文件中...

    UnixAgain 評論0 收藏0

發(fā)表評論

0條評論

neu

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<