Dubbo源码分析之服务消费实现

消费端的代码解析是从下面这段代码开始的

<dubbo:reference id="xxxService" interface="xxx.xxx.Service"/>

注解的方式的初始化入口是

ReferenceConfifig.get

public synchronized T get() {

checkAndUpdateSubConfigs(); //检查和修改配置

if (destroyed) {

throw new IllegalStateException("The invoker of ReferenceConfig(" +

url + ") has already destroyed!");

}

ReferenceAnnotationBeanPostProcessor->ReferenceBeanInvocationHandler.init-

>ReferenceConfig.get() 获得一个远程代理类init

初始化的过程,和服务发布的过程类似,会有特别多的判断以及参数的组装. 我们只需要关注

createProxy,创建代理类的方法。

if (ref == null) { //如果当前接口的远程代理引用为空,则进行初始化

init();

}

return ref;

}

private void init() {

//省略...

ref = createProxy(map);

//省略...

}

createProxy

代码比较长,但是逻辑相对比较清晰

1. 判断是否为本地调用,如果是则使用injvm协议进行调用

2. 判断是否为点对点调用,如果是则把url保存到urls集合中,如果url1,进入步骤4,如果urls>1

,则执行5

3. 如果是配置了注册中心,遍历注册中心,把url添加到urls集合,url1,进入步骤4,如果urls>1

,则执行5

4. 直连构建invoker

5. 构建invokers集合,通过cluster合并多个invoker

6. 最后调用 ProxyFactory 生成代理类

private T createProxy(Map<String, String> map) {

if (shouldJvmRefer(map)) { //判断是否是在同一个jvm进程中调用

URL url = new URL(Constants.LOCAL_PROTOCOL,

Constants.LOCALHOST_VALUE, 0, interfaceClass.getName()).addParameters(map);

invoker = refprotocol.refer(interfaceClass, url);

if (logger.isInfoEnabled()) {

logger.info("Using injvm service " + interfaceClass.getName());

}

} else {

//url 如果不为空,说明是点对点通信

if (url != null && url.length() > 0) { // user specified URL, could

be peer-to-peer address, or register center's address.

String[] us = Constants.SEMICOLON_SPLIT_PATTERN.split(url);if (us != null && us.length > 0) {

for (String u : us) {

URL url = URL.valueOf(u);

if (StringUtils.isEmpty(url.getPath())) {

url = url.setPath(interfaceName);

}

// 检测 url 协议是否为 registry,若是,表明用户想使用指定的注册

中心

if

(Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {

// map 转换为查询字符串,并作为 refer 参数的值添加到

url

urls.add(url.addParameterAndEncoded(Constants.REFER_KEY,

StringUtils.toQueryString(map)));

} else {

// 合并 url,移除服务提供者的一些配置(这些配置来源于用户配置

url 属性),

// 比如线程池相关配置。并保留服务提供者的部分配置,比如版本,

group,时间戳等

// 最后将合并后的配置设置为 url 查询字符串中。

urls.add(ClusterUtils.mergeUrl(url, map));

}

}

}

} else { // assemble URL from register center's configuration

checkRegistry(); //校验注册中心的配置以及是否有必要从配置中心组装url

//这里的代码实现和服务端类似,也是根据注册中心配置进行解析得到URL

//这里的URL肯定也是:

registry://ip:port/org.apache.dubbo.service.RegsitryService

List<URL> us = loadRegistries(false);

if (CollectionUtils.isNotEmpty(us)) {

for (URL u : us) {

URL monitorUrl = loadMonitor(u);

if (monitorUrl != null) {

map.put(Constants.MONITOR_KEY,

URL.encode(monitorUrl.toFullString()));

}

urls.add(u.addParameterAndEncoded(Constants.REFER_KEY,

StringUtils.toQueryString(map)));

}

}

//如果没有配置注册中心,则报错

if (urls.isEmpty()) {

throw new IllegalStateException("No such any registry to

reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() + "

use dubbo version " + Version.getVersion() + ", please config <dubbo:registry

address=\"...\" /> to your spring config.");

}

}

//如果值配置了一个注册中心或者一个服务提供者,直接使用refprotocol.refer

if (urls.size() == 1) {

invoker = refprotocol.refer(interfaceClass, urls.get(0));

} else {

List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();

URL registryURL = null;

for (URL url : urls) {//遍历urls生成多个invoker

invokers.add(refprotocol.refer(interfaceClass, url));protocol.refer

这里通过指定的协议来调用refer生成一个invoker对象,invoker前面讲过,它是一个代理对象。那么在

当前的消费端而言,invoker主要用于执行远程调用。

这个protocol,又是一个自适应扩展点,它得到的是一个Protocol$Adaptive.

if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {

registryURL = url; // use last registry url

}

}

if (registryURL != null) { //如果registryUrl不为空,构建静态

directory

// 使用RegistryAwareCluster

URL u = registryURL.addParameter(Constants.CLUSTER_KEY,

RegistryAwareCluster.NAME);

// 通过Cluster将多个invoker合并

RegistryAwareClusterInvoker(StaticDirectory) ->

FailoverClusterInvoker(RegistryDirectory, will execute route) -> Invoker

invoker = cluster.join(new StaticDirectory(u, invokers));

} else {

invoker = cluster.join(new StaticDirectory(invokers));

}

}

}

//检查invoker的有效性

if (shouldCheck() && !invoker.isAvailable()) {

// make it possible for consumer to retry later if provider is

temporarily unavailable

initialized = false;

throw new IllegalStateException("Failed to check the status of the

service " + interfaceName + ". No provider available for the service " + (group

== null ? "" : group + "/") + interfaceName + (version == null ? "" : ":" +

version) + " from the url " + invoker.getUrl() + " to the consumer " +

NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion());

}

if (logger.isInfoEnabled()) {

logger.info("Refer dubbo service " + interfaceClass.getName() + "

from url " + invoker.getUrl());

}

/**

* @since 2.7.0

* ServiceData Store

*/

MetadataReportService metadataReportService = null;

if ((metadataReportService = getMetadataReportService()) != null) {

URL consumerURL = new URL(Constants.CONSUMER_PROTOCOL,

map.remove(Constants.REGISTER_IP_KEY), 0, map.get(Constants.INTERFACE_KEY),

map);

metadataReportService.publishConsumer(consumerURL);

}

// create service proxy

return (T) proxyFactory.getProxy(invoker);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值