Dubbo服务引用流程

在ReferenceBean中实现了InitializingBean、FactoryBean接口, 在bean实例化属性赋值之后会调用afterPropertiesSet方法, 获取bean时使用getObject方法, 并调用ReferenceConfig的init方法

public void afterPropertiesSet() throws Exception {
    ...
	// 做了一顿初始化, 就是通过application/registry创建对象
	...
}

init方法会为bean构建一个map, 然后创建代理对象

private T createProxy(Map<String, String> map) {
    URL tmpUrl = new URL("temp", "localhost", 0, map);
    boolean isJvmRefer;
    if (this.isInjvm() == null) { // 判断是否为本地服务引用
        if (this.url != null && this.url.length() > 0) {
            isJvmRefer = false;
        } else if (InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl)) {
            isJvmRefer = true;
        } else {
            isJvmRefer = false;
        }
    } else {
        isJvmRefer = this.isInjvm();
    }

    if (isJvmRefer) { 
    	// 如果是本地引用, 直接调用refer方法
        URL url = (new URL("injvm", "127.0.0.1", 0, this.interfaceClass.getName())).addParameters(map);
        this.invoker = refprotocol.refer(this.interfaceClass, url);
        if (logger.isInfoEnabled()) {
            logger.info("Using injvm service " + this.interfaceClass.getName());
        }
    } else {
    	// 其他协议远程调用
        URL u;
        URL url;
        if (this.url != null && this.url.length() > 0) {
        	// 从配置中心获取url 两种方式: 点对点 注册中心获取
            String[] us = Constants.SEMICOLON_SPLIT_PATTERN.split(this.url);
            if (us != null && us.length > 0) {
                String[] arr$ = us;
                int len$ = us.length;

                for(int i$ = 0; i$ < len$; ++i$) {
                    String u = arr$[i$];
                    URL url = URL.valueOf(u);
                    if (url.getPath() == null || url.getPath().length() == 0) {
                        url = url.setPath(this.interfaceName);
                    }
					// 如果是配置中心
                    if ("registry".equals(url.getProtocol())) {
                        this.urls.add(url.addParameterAndEncoded("refer", StringUtils.toQueryString(map)));
                    } else {
                        this.urls.add(ClusterUtils.mergeUrl(url, map));
                    }
                }
            }
        } else {
        	// 如果在配置文件没有指定url 获取注册地址列表
            List<URL> us = this.loadRegistries(false);
            if (us != null && !us.isEmpty()) {
                for(Iterator i$ = us.iterator(); i$.hasNext(); this.urls.add(u.addParameterAndEncoded("refer", StringUtils.toQueryString(map)))) {
                    u = (URL)i$.next();
                    // 监控中心地址
                    url = this.loadMonitor(u);
                    if (url != null) {
                        map.put("monitor", URL.encode(url.toFullString()));
                    }
                }
            }

            if (this.urls.isEmpty()) {
                throw new IllegalStateException("No such any registry to reference " + this.interfaceName + " on the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", please config <dubbo:registry address=\"...\" /> to your spring config.");
            }
        }

        if (this.urls.size() == 1) {
        	// 转换成invoker
            this.invoker = refprotocol.refer(this.interfaceClass, (URL)this.urls.get(0));
        } else {
            List<Invoker<?>> invokers = new ArrayList();
            URL registryURL = null;
            Iterator i$ = this.urls.iterator();

            while(i$.hasNext()) {
                url = (URL)i$.next();
                // 逐个转换
                invokers.add(refprotocol.refer(this.interfaceClass, url));
                if ("registry".equals(url.getProtocol())) {
                    registryURL = url;
                }
            }

            if (registryURL != null) {
            	// 有注册中心url 使用availableCluster
                u = registryURL.addParameter("cluster", "available");
                this.invoker = cluster.join(new StaticDirectory(u, invokers)); // 合并
            } else {
                this.invoker = cluster.join(new StaticDirectory(invokers)); // 合并
            }
        }
    }
	...
}

看一下RegistryProtocol的refer方法

public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
    url = url.setProtocol(url.getParameter("registry", "dubbo")).removeParameter("registry");
    Registry registry = this.registryFactory.getRegistry(url);
    if (RegistryService.class.equals(type)) {
        return this.proxyFactory.getInvoker(registry, type, url);
    } else {
        Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded("refer"));
        String group = (String)qs.get("group"); // 获取group参数
        return group == null || group.length() <= 0 || Constants.COMMA_SPLIT_PATTERN.split(group).length <= 1 && !"*".equals(group) ? this.doRefer(this.cluster, registry, type, url) : this.doRefer(this.getMergeableCluster(), registry, type, url);
    }
}
private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
    RegistryDirectory<T> directory = new RegistryDirectory(type, url);
    directory.setRegistry(registry);
    directory.setProtocol(this.protocol);
    Map<String, String> parameters = new HashMap(directory.getUrl().getParameters());
    URL subscribeUrl = new URL("consumer", (String)parameters.remove("register.ip"), 0, type.getName(), parameters);
    if (!"*".equals(url.getServiceInterface()) && url.getParameter("register", true)) {
    	// 如果是注册url. 注册消费者, 向zk创建节点
        registry.register(subscribeUrl.addParameters(new String[]{"category", "consumers", "check", String.valueOf(false)}));
    }
	// 订阅对应目录 
    directory.subscribe(subscribeUrl.addParameter("category", "providers,configurators,routers"));
    Invoker invoker = cluster.join(directory);
    ProviderConsumerRegTable.registerConsumer(invoker, url, subscribeUrl, directory);
    return invoker;
}

查看RegistryDirectory.subscribe订阅方法

public void subscribe(URL url) {
    this.setConsumerUrl(url);
    this.registry.subscribe(url, this); // 将自己当做listener传给zk 实现了NotifyListener接口
}

// 当有订阅的相关目录产生变化后, 会调用此方法
public synchronized void notify(List<URL> urls) {
	// 获取以下信息
    List<URL> invokerUrls = new ArrayList();
    List<URL> routerUrls = new ArrayList();
    List<URL> configuratorUrls = new ArrayList();
    Iterator i$ = urls.iterator();

    while(true) {
        while(true) {
            while(i$.hasNext()) {
                URL url = (URL)i$.next();
                String protocol = url.getProtocol();
                String category = url.getParameter("category", "providers");
                if (!"routers".equals(category) && !"route".equals(protocol)) {
                    if (!"configurators".equals(category) && !"override".equals(protocol)) {
                        if ("providers".equals(category)) {
                            invokerUrls.add(url);
                        } else {
                            logger.warn("Unsupported category " + category + " in notified url: " + url + " from registry " + this.getUrl().getAddress() + " to consumer " + NetUtils.getLocalHost());
                        }
                    } else {
                        configuratorUrls.add(url);
                    }
                } else {
                    routerUrls.add(url);
                }
            }

            if (configuratorUrls != null && !configuratorUrls.isEmpty()) {
                this.configurators = toConfigurators(configuratorUrls);
            }

            List localConfigurators;
            if (routerUrls != null && !routerUrls.isEmpty()) {
                localConfigurators = this.toRouters(routerUrls);
                if (localConfigurators != null) {
                    this.setRouters(localConfigurators);
                }
            }

            localConfigurators = this.configurators;
            this.overrideDirectoryUrl = this.directoryUrl;
            Configurator configurator;
            if (localConfigurators != null && !localConfigurators.isEmpty()) {
                for(Iterator i$ = localConfigurators.iterator(); i$.hasNext(); this.overrideDirectoryUrl = configurator.configure(this.overrideDirectoryUrl)) {
                    configurator = (Configurator)i$.next();
                }
            }
			// 刷新Invoker
            this.refreshInvoker(invokerUrls);
            return;
        }
    }
}

刷新invoker会调用DubboProtocol的refer方法
方法内会根据url信息创建netty客户端, 用于通讯, 至此服务引用完成

参考
添加链接描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值