国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

dubbo源碼解析(三十七)集群——directory

blastz / 836人閱讀

摘要:首先將根據路由規則服務提供者和配置規則三種類型分開,分別放入三個集合,然后對每個集合進行修改或者通知設置禁止訪問置空關閉所有的關閉禁止訪問引用老的傳入的為空,說明是路由規則或配置規則發生改變,此時是空的,直接使用。

集群——directory
目標:介紹dubbo中集群的目錄,介紹dubbo-cluster下directory包的源碼。
前言

我在前面的文章中也提到了Directory可以看成是多個Invoker的集合,Directory 的用途是保存 Invoker,其實現類 RegistryDirectory 是一個動態服務目錄,可感知注冊中心配置的變化,它所持有的 Inovker 列表會隨著注冊中心內容的變化而變化。每次變化后,RegistryDirectory 會動態增刪 Inovker,那在之前文章中我忽略了RegistryDirectory的源碼分析,在本文中來補充。

源碼分析 (一)AbstractDirectory

該類實現了Directory接口,

1.屬性
// logger
private static final Logger logger = LoggerFactory.getLogger(AbstractDirectory.class);

/**
 * url對象
 */
private final URL url;

/**
 * 是否銷毀
 */
private volatile boolean destroyed = false;

/**
 * 消費者端url
 */
private volatile URL consumerUrl;

/**
 * 路由集合
 */
private volatile List routers;
2.list
@Override
public List> list(Invocation invocation) throws RpcException {
    // 如果銷毀,則拋出異常
    if (destroyed) {
        throw new RpcException("Directory already destroyed .url: " + getUrl());
    }
    // 調用doList來獲得Invoker集合
    List> invokers = doList(invocation);
    // 獲得路由集合
    List 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)) {
                    // 根據路由規則選擇符合規則的invoker集合
                    invokers = router.route(invokers, getConsumerUrl(), invocation);
                }
            } catch (Throwable t) {
                logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t);
            }
        }
    }
    return invokers;
}

該方法是生成invoker集合的邏輯實現。其中doList是抽象方法,交由子類來實現。

3.setRouters
protected void setRouters(List routers) {
    // copy list
    // 復制路由集合
    routers = routers == null ? new ArrayList() : new ArrayList(routers);
    // append url router
    // 獲得路由的配置
    String routerkey = url.getParameter(Constants.ROUTER_KEY);
    if (routerkey != null && routerkey.length() > 0) {
        // 加載路由工廠
        RouterFactory routerFactory = ExtensionLoader.getExtensionLoader(RouterFactory.class).getExtension(routerkey);
        // 加入集合
        routers.add(routerFactory.getRouter(url));
    }
    // append mock invoker selector
    // 加入服務降級路由
    routers.add(new MockInvokersSelector());
    // 排序
    Collections.sort(routers);
    this.routers = routers;
}
(二)StaticDirectory

靜態 Directory 實現類,將傳入的 invokers 集合,封裝成靜態的 Directory 對象。

public class StaticDirectory extends AbstractDirectory {

    private final List> invokers;

    public StaticDirectory(List> invokers) {
        this(null, invokers, null);
    }

    public StaticDirectory(List> invokers, List routers) {
        this(null, invokers, routers);
    }

    public StaticDirectory(URL url, List> invokers) {
        this(url, invokers, null);
    }

    public StaticDirectory(URL url, List> invokers, List routers) {
        super(url == null && invokers != null && !invokers.isEmpty() ? invokers.get(0).getUrl() : url, routers);
        if (invokers == null || invokers.isEmpty())
            throw new IllegalArgumentException("invokers == null");
        this.invokers = invokers;
    }

    @Override
    public Class getInterface() {
        return invokers.get(0).getInterface();
    }

    @Override
    public boolean isAvailable() {
        if (isDestroyed()) {
            return false;
        }
        // 遍歷invokers,如果有一個可用,則可用
        for (Invoker invoker : invokers) {
            if (invoker.isAvailable()) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void destroy() {
        if (isDestroyed()) {
            return;
        }
        super.destroy();
        // 遍歷invokers,銷毀所有的invoker
        for (Invoker invoker : invokers) {
            invoker.destroy();
        }
        // 清除集合
        invokers.clear();
    }

    @Override
    protected List> doList(Invocation invocation) throws RpcException {

        return invokers;
    }

}

該類我就不多講解,比較簡單。

(三)RegistryDirectory

該類繼承了AbstractDirectory類,是基于注冊中心的動態 Directory 實現類,會根據注冊中心的推送變更 List

1.屬性
private static final Logger logger = LoggerFactory.getLogger(RegistryDirectory.class);

/**
 * cluster實現類對象
 */
private static final Cluster cluster = ExtensionLoader.getExtensionLoader(Cluster.class).getAdaptiveExtension();

/**
 * 路由工廠
 */
private static final RouterFactory routerFactory = ExtensionLoader.getExtensionLoader(RouterFactory.class).getAdaptiveExtension();

/**
 * 配置規則工廠
 */
private static final ConfiguratorFactory configuratorFactory = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class).getAdaptiveExtension();

/**
 * 服務key
 */
private final String serviceKey; // Initialization at construction time, assertion not null
/**
 * 服務類型
 */
private final Class serviceType; // Initialization at construction time, assertion not null
/**
 * 消費者URL的配置項 Map
 */
private final Map queryMap; // Initialization at construction time, assertion not null
/**
 * 原始的目錄 URL
 */
private final URL directoryUrl; // Initialization at construction time, assertion not null, and always assign non null value
/**
 * 服務方法集合
 */
private final String[] serviceMethods;
/**
 * 是否使用多分組
 */
private final boolean multiGroup;
/**
 * 協議
 */
private Protocol protocol; // Initialization at the time of injection, the assertion is not null
/**
 * 注冊中心
 */
private Registry registry; // Initialization at the time of injection, the assertion is not null
/**
 *  是否禁止訪問
 */
private volatile boolean forbidden = false;

/**
 * 覆蓋目錄的url
 */
private volatile URL overrideDirectoryUrl; // Initialization at construction time, assertion not null, and always assign non null value

/**
 * override rules
 * Priority: override>-D>consumer>provider
 * Rule one: for a certain provider 
 * Rule two: for all providers <* ,timeout=5000>
 * 配置規則數組
 */
private volatile List configurators; // The initial value is null and the midway may be assigned to null, please use the local variable reference

// Map cache service url to invoker mapping.
/**
 * url與服務提供者 Invoker 集合的映射緩存
 */
private volatile Map> urlInvokerMap; // The initial value is null and the midway may be assigned to null, please use the local variable reference

// Map cache service method to invokers mapping.
/**
 * 方法名和服務提供者 Invoker 集合的映射緩存
 */
private volatile Map>> methodInvokerMap; // The initial value is null and the midway may be assigned to null, please use the local variable reference

// Set cache invokeUrls to invokers mapping.
/**
 * 服務提供者Invoker 集合緩存
 */
private volatile Set cachedInvokerUrls; // The initial value is null and the midway may be assigned to null, please use the local variable reference
2.toConfigurators
public static List toConfigurators(List urls) {
    // 如果為空,則返回空集合
    if (urls == null || urls.isEmpty()) {
        return Collections.emptyList();
    }

    List configurators = new ArrayList(urls.size());
    // 遍歷url集合
    for (URL url : urls) {
        //如果是協議是empty的值,則清空配置集合
        if (Constants.EMPTY_PROTOCOL.equals(url.getProtocol())) {
            configurators.clear();
            break;
        }
        // 覆蓋的參數集合
        Map override = new HashMap(url.getParameters());
        //The anyhost parameter of override may be added automatically, it can"t change the judgement of changing url
        // 覆蓋的anyhost參數可以自動添加,也不能改變更改url的判斷
        override.remove(Constants.ANYHOST_KEY);
        // 如果需要覆蓋添加的值為0,則清空配置
        if (override.size() == 0) {
            configurators.clear();
            continue;
        }
        // 加入配置規則集合
        configurators.add(configuratorFactory.getConfigurator(url));
    }
    // 排序
    Collections.sort(configurators);
    return configurators;
}

該方法是處理配置規則url集合,轉換覆蓋url映射以便在重新引用時使用,每次發送所有規則,網址將被重新組裝和計算。

3.destroy
@Override
public void destroy() {
    // 如果銷毀了,則返回
    if (isDestroyed()) {
        return;
    }
    // unsubscribe.
    try {
        if (getConsumerUrl() != null && registry != null && registry.isAvailable()) {
            // 取消訂閱
            registry.unsubscribe(getConsumerUrl(), this);
        }
    } catch (Throwable t) {
        logger.warn("unexpeced error when unsubscribe service " + serviceKey + "from registry" + registry.getUrl(), t);
    }
    super.destroy(); // must be executed after unsubscribing
    try {
        // 清空所有的invoker
        destroyAllInvokers();
    } catch (Throwable t) {
        logger.warn("Failed to destroy service " + serviceKey, t);
    }
}

該方法是銷毀方法。

4.destroyAllInvokers
private void destroyAllInvokers() {
    Map> localUrlInvokerMap = this.urlInvokerMap; // local reference
    // 如果invoker集合不為空
    if (localUrlInvokerMap != null) {
        // 遍歷
        for (Invoker invoker : new ArrayList>(localUrlInvokerMap.values())) {
            try {
                // 銷毀invoker
                invoker.destroy();
            } catch (Throwable t) {
                logger.warn("Failed to destroy service " + serviceKey + " to provider " + invoker.getUrl(), t);
            }
        }
        // 清空集合
        localUrlInvokerMap.clear();
    }
    methodInvokerMap = null;
}

該方法是關閉所有的invoker服務。

5.notify
@Override
public synchronized void notify(List urls) {
    List invokerUrls = new ArrayList();
    List routerUrls = new ArrayList();
    List configuratorUrls = new ArrayList();
    // 遍歷url
    for (URL url : urls) {
        // 獲得協議
        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)) {
            // 則在路由規則集合中加入
            routerUrls.add(url);
        } else if (Constants.CONFIGURATORS_CATEGORY.equals(category)
                || Constants.OVERRIDE_PROTOCOL.equals(protocol)) {
            // 如果是配置規則,則加入配置規則集合
            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());
        }
    }
    // configurators
    if (configuratorUrls != null && !configuratorUrls.isEmpty()) {
        // 處理配置規則url集合
        this.configurators = toConfigurators(configuratorUrls);
    }
    // routers
    if (routerUrls != null && !routerUrls.isEmpty()) {
        // 處理路由規則 URL 集合
        List routers = toRouters(routerUrls);
        if (routers != null) { // null - do nothing
            // 并且設置路由集合
            setRouters(routers);
        }
    }
    List localConfigurators = this.configurators; // local reference
    // merge override parameters
    this.overrideDirectoryUrl = directoryUrl;
    if (localConfigurators != null && !localConfigurators.isEmpty()) {
        // 遍歷配置規則集合 逐個進行配置
        for (Configurator configurator : localConfigurators) {
            this.overrideDirectoryUrl = configurator.configure(overrideDirectoryUrl);
        }
    }
    // providers
    // 處理服務提供者 URL 集合
    refreshInvoker(invokerUrls);
}

當服務有變化的時候,執行該方法。首先將url根據路由規則、服務提供者和配置規則三種類型分開,分別放入三個集合,然后對每個集合進行修改或者通知

6.refreshInvoker
private void refreshInvoker(List invokerUrls) {
    if (invokerUrls != null && invokerUrls.size() == 1 && invokerUrls.get(0) != null
            && Constants.EMPTY_PROTOCOL.equals(invokerUrls.get(0).getProtocol())) {
        // 設置禁止訪問
        this.forbidden = true; // Forbid to access
        // methodInvokerMap 置空
        this.methodInvokerMap = null; // Set the method invoker map to null
        // 關閉所有的invoker
        destroyAllInvokers(); // Close all invokers
    } else {
        // 關閉禁止訪問
        this.forbidden = false; // Allow to access
        // 引用老的 urlInvokerMap
        Map> oldUrlInvokerMap = this.urlInvokerMap; // local reference
        // 傳入的 invokerUrls 為空,說明是路由規則或配置規則發生改變,此時 invokerUrls 是空的,直接使用 cachedInvokerUrls 。
        if (invokerUrls.isEmpty() && this.cachedInvokerUrls != null) {
            invokerUrls.addAll(this.cachedInvokerUrls);
        } else {
            // 否則把所有的invokerUrls加入緩存
            this.cachedInvokerUrls = new HashSet();
            this.cachedInvokerUrls.addAll(invokerUrls);//Cached invoker urls, convenient for comparison
        }
        // 如果invokerUrls為空,則直接返回
        if (invokerUrls.isEmpty()) {
            return;
        }
        // 將傳入的 invokerUrls ,轉成新的 urlInvokerMap
        Map> newUrlInvokerMap = toInvokers(invokerUrls);// Translate url list to Invoker map
        // 轉換出新的 methodInvokerMap
        Map>> newMethodInvokerMap = toMethodInvokers(newUrlInvokerMap); // Change method name to map Invoker Map
        // state change
        // If the calculation is wrong, it is not processed.
        // 如果為空,則打印錯誤日志并且返回
        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;
        }
        // 若服務引用多 group ,則按照 method + group 聚合 Invoker 集合
        this.methodInvokerMap = multiGroup ? toMergeMethodInvokerMap(newMethodInvokerMap) : newMethodInvokerMap;
        this.urlInvokerMap = newUrlInvokerMap;
        try {
            // 銷毀不再使用的 Invoker 集合
            destroyUnusedInvokers(oldUrlInvokerMap, newUrlInvokerMap); // Close the unused Invoker
        } catch (Exception e) {
            logger.warn("destroyUnusedInvokers error. ", e);
        }
    }
}

該方法是處理服務提供者 URL 集合。根據 invokerURL 列表轉換為 invoker 列表。轉換規則如下:

如果 url 已經被轉換為 invoker ,則不在重新引用,直接從緩存中獲取,注意如果 url 中任何一個參數變更也會重新引用。

如果傳入的 invoker 列表不為空,則表示最新的 invoker 列表。

如果傳入的 invokerUrl 列表是空,則表示只是下發的 override 規則或 route 規則,需要重新交叉對比,決定是否需要重新引用。

7.toMergeMethodInvokerMap
private Map>> toMergeMethodInvokerMap(Map>> methodMap) {
    // 循環方法,按照 method + group 聚合 Invoker 集合
    Map>> result = new HashMap>>();
    // 遍歷方法集合
    for (Map.Entry>> entry : methodMap.entrySet()) {
        // 獲得方法
        String method = entry.getKey();
        // 獲得invoker集合
        List> invokers = entry.getValue();
        // 獲得組集合
        Map>> groupMap = new HashMap>>();
        // 遍歷invoker集合
        for (Invoker invoker : invokers) {
            // 獲得url攜帶的組配置
            String group = invoker.getUrl().getParameter(Constants.GROUP_KEY, "");
            // 獲得該組對應的invoker集合
            List> groupInvokers = groupMap.get(group);
            // 如果為空,則新創建一個,然后加入集合
            if (groupInvokers == null) {
                groupInvokers = new ArrayList>();
                groupMap.put(group, groupInvokers);
            }
            groupInvokers.add(invoker);
        }
        // 如果只有一個組
        if (groupMap.size() == 1) {
            // 返回該組的invoker集合
            result.put(method, groupMap.values().iterator().next());
        } else if (groupMap.size() > 1) {
            // 如果不止一個組
            List> groupInvokers = new ArrayList>();
            // 遍歷組
            for (List> groupList : groupMap.values()) {
                // 每次從集群中選擇一個invoker加入groupInvokers
                groupInvokers.add(cluster.join(new StaticDirectory(groupList)));
            }
            // 加入需要返回的集合
            result.put(method, groupInvokers);
        } else {
            result.put(method, invokers);
        }
    }
    return result;
}

該方法是通過按照 method + group 來聚合 Invoker 集合。

8.toRouters
private List toRouters(List urls) {
    List routers = new ArrayList();
    // 如果為空,則直接返回空集合
    if (urls == null || urls.isEmpty()) {
        return routers;
    }
    if (urls != null && !urls.isEmpty()) {
        // 遍歷url集合
        for (URL url : urls) {
            // 如果為empty協議,則直接跳過
            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;
}

該方法是對url集合進行路由的解析,返回路由集合。

9.toInvokers
private Map> toInvokers(List urls) {
    Map> newUrlInvokerMap = new HashMap>();
    // 如果為空,則返回空集合
    if (urls == null || urls.isEmpty()) {
        return newUrlInvokerMap;
    }
    Set keys = new HashSet();
    // 獲得引用服務的協議
    String queryProtocols = this.queryMap.get(Constants.PROTOCOL_KEY);
    // 遍歷url
    for (URL providerUrl : urls) {
        // If protocol is configured at the reference side, only the matching protocol is selected
        // 如果在參考側配置協議,則僅選擇匹配協議
        if (queryProtocols != null && queryProtocols.length() > 0) {
            boolean accept = false;
            // 分割協議
            String[] acceptProtocols = queryProtocols.split(",");
            // 遍歷協議
            for (String acceptProtocol : acceptProtocols) {
                // 如果匹配,則是接受的協議
                if (providerUrl.getProtocol().equals(acceptProtocol)) {
                    accept = true;
                    break;
                }
            }
            if (!accept) {
                continue;
            }
        }
        // 如果協議是empty,則跳過
        if (Constants.EMPTY_PROTOCOL.equals(providerUrl.getProtocol())) {
            continue;
        }
        // 如果該協議不是dubbo支持的,則打印錯誤日志,跳過
        if (!ExtensionLoader.getExtensionLoader(Protocol.class).hasExtension(providerUrl.getProtocol())) {
            logger.error(new IllegalStateException("Unsupported protocol " + providerUrl.getProtocol() + " in notified url: " + providerUrl + " from registry " + getUrl().getAddress() + " to consumer " + NetUtils.getLocalHost()
                    + ", supported protocol: " + ExtensionLoader.getExtensionLoader(Protocol.class).getSupportedExtensions()));
            continue;
        }
        // 合并url參數
        URL url = mergeUrl(providerUrl);

        String key = url.toFullString(); // The parameter urls are sorted
        if (keys.contains(key)) { // Repeated url
            continue;
        }
        // 添加到keys
        keys.add(key);
        // Cache key is url that does not merge with consumer side parameters, regardless of how the consumer combines parameters, if the server url changes, then refer again
        // 如果服務端 URL 發生變化,則重新 refer 引用
        Map> localUrlInvokerMap = this.urlInvokerMap; // local reference
        Invoker invoker = localUrlInvokerMap == null ? null : localUrlInvokerMap.get(key);
        if (invoker == null) { // Not in the cache, refer again
            try {
                // 判斷是否開啟
                boolean enabled = true;
                // 獲得enabled配置
                if (url.hasParameter(Constants.DISABLED_KEY)) {
                    enabled = !url.getParameter(Constants.DISABLED_KEY, false);
                } else {
                    enabled = url.getParameter(Constants.ENABLED_KEY, true);
                }
                // 若開啟,創建 Invoker 對象
                if (enabled) {
                    invoker = new InvokerDelegate(protocol.refer(serviceType, url), url, providerUrl);
                }
            } catch (Throwable t) {
                logger.error("Failed to refer invoker for interface:" + serviceType + ",url:(" + url + ")" + t.getMessage(), t);
            }
            // 添加到 newUrlInvokerMap 中
            if (invoker != null) { // Put new invoker in cache
                newUrlInvokerMap.put(key, invoker);
            }
        } else {
            newUrlInvokerMap.put(key, invoker);
        }
    }
    // 清空 keys
    keys.clear();
    return newUrlInvokerMap;
}

該方法是將url轉換為調用者,如果url已被引用,則不會重新引用。

10.mergeUrl
private URL mergeUrl(URL providerUrl) {
    // 合并消費端參數
    providerUrl = ClusterUtils.mergeUrl(providerUrl, queryMap); // Merge the consumer side parameters

    // 合并配置規則
    List localConfigurators = this.configurators; // local reference
    if (localConfigurators != null && !localConfigurators.isEmpty()) {
        for (Configurator configurator : localConfigurators) {
            providerUrl = configurator.configure(providerUrl);
        }
    }

    // 不檢查連接是否成功,總是創建 Invoker
    providerUrl = providerUrl.addParameter(Constants.CHECK_KEY, String.valueOf(false)); // Do not check whether the connection is successful or not, always create Invoker!

    // The combination of directoryUrl and override is at the end of notify, which can"t be handled here
    // 合并提供者參數,因為 directoryUrl 與 override 合并是在 notify 的最后,這里不能夠處理
    this.overrideDirectoryUrl = this.overrideDirectoryUrl.addParametersIfAbsent(providerUrl.getParameters()); // Merge the provider side parameters

    // 1.0版本兼容
    if ((providerUrl.getPath() == null || providerUrl.getPath().length() == 0)
            && "dubbo".equals(providerUrl.getProtocol())) { // Compatible version 1.0
        //fix by tony.chenl DUBBO-44
        String path = directoryUrl.getParameter(Constants.INTERFACE_KEY);
        if (path != null) {
            int i = path.indexOf("/");
            if (i >= 0) {
                path = path.substring(i + 1);
            }
            i = path.lastIndexOf(":");
            if (i >= 0) {
                path = path.substring(0, i);
            }
            providerUrl = providerUrl.setPath(path);
        }
    }
    return providerUrl;
}

該方法是合并 URL 參數,優先級為配置規則 > 服務消費者配置 > 服務提供者配置.

11.toMethodInvokers
private Map>> toMethodInvokers(Map> invokersMap) {
    Map>> newMethodInvokerMap = new HashMap>>();
    // According to the methods classification declared by the provider URL, the methods is compatible with the registry to execute the filtered methods
    List> invokersList = new ArrayList>();
    if (invokersMap != null && invokersMap.size() > 0) {
        // 遍歷調用者列表
        for (Invoker invoker : invokersMap.values()) {
            String parameter = invoker.getUrl().getParameter(Constants.METHODS_KEY);
            // 按服務提供者 URL 所聲明的 methods 分類
            if (parameter != null && parameter.length() > 0) {
                // 分割參數得到方法集合
                String[] methods = Constants.COMMA_SPLIT_PATTERN.split(parameter);
                if (methods != null && methods.length > 0) {
                    // 遍歷方法集合
                    for (String method : methods) {
                        if (method != null && method.length() > 0
                                && !Constants.ANY_VALUE.equals(method)) {
                            // 獲得該方法對應的invoker,如果為空,則創建
                            List> methodInvokers = newMethodInvokerMap.get(method);
                            if (methodInvokers == null) {
                                methodInvokers = new ArrayList>();
                                newMethodInvokerMap.put(method, methodInvokers);
                            }
                            methodInvokers.add(invoker);
                        }
                    }
                }
            }
            invokersList.add(invoker);
        }
    }
    // 根據路由規則,匹配合適的 Invoker 集合。
    List> newInvokersList = route(invokersList, null);
    // 添加 `newInvokersList` 到 `newMethodInvokerMap` 中,表示該服務提供者的全量 Invoker 集合
    newMethodInvokerMap.put(Constants.ANY_VALUE, newInvokersList);
    if (serviceMethods != null && serviceMethods.length > 0) {
        // 循環方法,獲得每個方法路由匹配的invoker集合
        for (String method : serviceMethods) {
            List> methodInvokers = newMethodInvokerMap.get(method);
            if (methodInvokers == null || methodInvokers.isEmpty()) {
                methodInvokers = newInvokersList;
            }
            newMethodInvokerMap.put(method, route(methodInvokers, method));
        }
    }
    // sort and unmodifiable
    // 循環排序每個方法的 Invoker 集合,排序
    for (String method : new HashSet(newMethodInvokerMap.keySet())) {
        List> methodInvokers = newMethodInvokerMap.get(method);
        Collections.sort(methodInvokers, InvokerComparator.getComparator());
        newMethodInvokerMap.put(method, Collections.unmodifiableList(methodInvokers));
    }
    // 設置為不可變
    return Collections.unmodifiableMap(newMethodInvokerMap);
}

該方法是將調用者列表轉換為與方法的映射關系。

12.destroyUnusedInvokers
private void destroyUnusedInvokers(Map> oldUrlInvokerMap, Map> newUrlInvokerMap) {
    if (newUrlInvokerMap == null || newUrlInvokerMap.size() == 0) {
        destroyAllInvokers();
        return;
    }
    // check deleted invoker
    // 記錄已經刪除的invoker
    List deleted = null;
    if (oldUrlInvokerMap != null) {
        Collection> newInvokers = newUrlInvokerMap.values();
        // 遍歷舊的invoker集合
        for (Map.Entry> entry : oldUrlInvokerMap.entrySet()) {
            if (!newInvokers.contains(entry.getValue())) {
                if (deleted == null) {
                    deleted = new ArrayList();
                }
                // 加入該invoker
                deleted.add(entry.getKey());
            }
        }
    }

    if (deleted != null) {
        // 遍歷需要刪除的invoker  url集合
        for (String url : deleted) {
            if (url != null) {
                // 移除該url
                Invoker invoker = oldUrlInvokerMap.remove(url);
                if (invoker != null) {
                    try {
                        // 銷毀invoker
                        invoker.destroy();
                        if (logger.isDebugEnabled()) {
                            logger.debug("destroy invoker[" + invoker.getUrl() + "] success. ");
                        }
                    } catch (Exception e) {
                        logger.warn("destroy invoker[" + invoker.getUrl() + "] faild. " + e.getMessage(), e);
                    }
                }
            }
        }
    }
}

該方法是銷毀不再使用的 Invoker 集合。

13.doList
@Override
public List> doList(Invocation invocation) {
    // 如果禁止訪問,則拋出異常
    if (forbidden) {
        // 1. No service provider 2. Service providers are disabled
        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; // local reference
    if (localMethodInvokerMap != null && localMethodInvokerMap.size() > 0) {
        // 獲得方法名
        String methodName = RpcUtils.getMethodName(invocation);
        // 獲得參數名
        Object[] args = RpcUtils.getArguments(invocation);
        if (args != null && args.length > 0 && args[0] != null
                && (args[0] instanceof String || args[0].getClass().isEnum())) {
            // 根據第一個參數枚舉路由
            invokers = localMethodInvokerMap.get(methodName + "." + args[0]); // The routing can be enumerated according to the first parameter
        }
        if (invokers == null) {
            // 根據方法名獲得 Invoker 集合
            invokers = localMethodInvokerMap.get(methodName);
        }
        if (invokers == null) {
            // 使用全量 Invoker 集合。例如,`#$echo(name)` ,回聲方法
            invokers = localMethodInvokerMap.get(Constants.ANY_VALUE);
        }
        if (invokers == null) {
            // 使用 `methodInvokerMap` 第一個 Invoker 集合。防御性編程。
            Iterator>> iterator = localMethodInvokerMap.values().iterator();
            if (iterator.hasNext()) {
                invokers = iterator.next();
            }
        }
    }
    return invokers == null ? new ArrayList>(0) : invokers;
}

該方法是通過會話域來獲得Invoker集合。

后記
該部分相關的源碼解析地址:https://github.com/CrazyHZM/i...

該文章講解了集群中關于directory實現的部分,關鍵是RegistryDirectory,其中涉及到眾多方法,需要好好品味。接下來我將開始對集群模塊關于loadbalance部分進行講解。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/77406.html

相關文章

  • dubbo源碼解析三十九)集群——merger

    摘要:源碼分析一創建該類實現了接口,是分組集合的集群實現。三工廠類,獲得指定類型的對象。后記該部分相關的源碼解析地址該文章講解了集群中關于分組聚合實現的部分。接下來我將開始對集群模塊關于路由部分進行講解。 集群——merger 目標:介紹dubbo中集群的分組聚合,介紹dubbo-cluster下merger包的源碼。 前言 按組合并返回結果 ,比如菜單服務,接口一樣,但有多種實現,用gro...

    lscho 評論0 收藏0
  • dubbo源碼解析三十五)集群——cluster

    摘要:失敗安全,出現異常時,直接忽略。失敗自動恢復,在調用失敗后,返回一個空結果給服務提供者。源碼分析一該類實現了接口,是集群的抽象類。 集群——cluster 目標:介紹dubbo中集群容錯的幾種模式,介紹dubbo-cluster下support包的源碼。 前言 集群容錯還是很好理解的,就是當你調用失敗的時候所作出的措施。先來看看有哪些模式: showImg(https://segmen...

    gself 評論0 收藏0
  • dubbo源碼解析(四十八)異步化改造

    摘要:大揭秘異步化改造目標從源碼的角度分析的新特性中對于異步化的改造原理。看源碼解析四十六消費端發送請求過程講到的十四的,在以前的邏輯會直接在方法中根據配置區分同步異步單向調用。改為關于可以參考源碼解析十遠程通信層的六。 2.7大揭秘——異步化改造 目標:從源碼的角度分析2.7的新特性中對于異步化的改造原理。 前言 dubbo中提供了很多類型的協議,關于協議的系列可以查看下面的文章: du...

    lijinke666 評論0 收藏0
  • dubbo源碼解析(四十六)消費端發送請求過程

    摘要:可以參考源碼解析二十四遠程調用協議的八。十六的該類也是用了適配器模式,該類主要的作用就是增加了心跳功能,可以參考源碼解析十遠程通信層的四。二十的可以參考源碼解析十七遠程通信的一。 2.7大揭秘——消費端發送請求過程 目標:從源碼的角度分析一個服務方法調用經歷怎么樣的磨難以后到達服務端。 前言 前一篇文章講到的是引用服務的過程,引用服務無非就是創建出一個代理。供消費者調用服務的相關方法。...

    fish 評論0 收藏0
  • dubbo源碼解析三十八)集群——LoadBalance

    摘要:集群目標介紹中集群的負載均衡,介紹下包的源碼。源碼分析一該類實現了接口,是負載均衡的抽象類,提供了權重計算的功能。四該類是負載均衡基于一致性的邏輯實現。 集群——LoadBalance 目標:介紹dubbo中集群的負載均衡,介紹dubbo-cluster下loadBalance包的源碼。 前言 負載均衡,說的通俗點就是要一碗水端平。在這個時代,公平是很重要的,在網絡請求的時候同樣是這個...

    不知名網友 評論0 收藏0

發表評論

0條評論

blastz

|高級講師

TA的文章

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