博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Dubbo之服务引用
阅读量:5909 次
发布时间:2019-06-19

本文共 6295 字,大约阅读时间需要 20 分钟。

  hot3.png

概述

引用服务是指服务的消费者向注册中心查询提供者的信息或者自己配置提供者的信息,然后根据提供者的信息,将远程通信的逻辑封装到一个代理对象里,等待业务方进行调用。逻辑上分为两步:

  1. url --> Invoker,使用Protocol#refer()
  2. Invoker --> proxy(代理了远程通信等逻辑),使用ProxyFactory#getProxy()

ReferenceConfig

暴露服务的逻辑在ReferenceConfig#createProxy()ReferenceConfig表示<dubbo:reference />

if (urls.size() == 1) {    invoker = refprotocol.refer(interfaceClass, urls.get(0));} else {    // 多个urls,循环产生Invoker,并最终用Cluster合并成一个Invoker,变成一个集群Invoker    List
> invokers = new ArrayList
>(); URL registryURL = null; for (URL url : urls) { invokers.add(refprotocol.refer(interfaceClass, url)); if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { registryURL = url; // use last registry url // 如果有多个注册中心,用最后一个 } } if (registryURL != null) { // registry url is available // use AvailableCluster only when register's cluster is available // 对有注册中心的 Cluster 只用 AvailableCluster URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME); invoker = cluster.join(new StaticDirectory(u, invokers)); } else { // not a registry url invoker = cluster.join(new StaticDirectory(invokers)); }}

urls里可以是提供者url也可以是注册中心url

  • 直接是提供者,解析出的url是比如:dubbo://service-host/com.foo.FooService?version=1.0.0,根据扩展自适配机制,使用DubboProtocol
  • 注册中心,解析出的url是:registry://registry-host/com.alibaba.dubbo.registry.RegistryService?refer=URL.encode("consumer://consumer-host/com.foo.FooService?version=1.0.0"),根据扩展自适配机制,首先使用的RegistryProtocol,在refer()方法里向注册中心订阅提供者信息,订阅到信息之后,根据提供者的url是比如:dubbo://service-host/com.foo.FooService?version=1.0.0,使用DubboProtocol

RegistryProtocol

向注册中心订阅提供者信息,由注册中心推送提供者的信息。

/** * * @param cluster 自适应扩展实现 * @param registry 注册中心对象 * @param type 服务接口类型 * @param url 注册中心url * @param 
* @return */private
Invoker
doRefer(Cluster cluster, Registry registry, Class
type, URL url) { RegistryDirectory
directory = new RegistryDirectory
(type, url); directory.setRegistry(registry); directory.setProtocol(protocol); // all attributes of REFER_KEY Map
parameters = new HashMap
(directory.getUrl().getParameters()); // 订阅url URL subscribeUrl = new URL(Constants.CONSUMER_PROTOCOL, parameters.remove(Constants.REGISTER_IP_KEY), 0, type.getName(), parameters); // 向注册中心注册自己(服务消费者) if (!Constants.ANY_VALUE.equals(url.getServiceInterface()) && url.getParameter(Constants.REGISTER_KEY, true)) { registry.register(subscribeUrl.addParameters(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY, Constants.CHECK_KEY, String.valueOf(false))); } // 向注册中心订阅信息,包含提供者、配置、路由 directory.subscribe(subscribeUrl.addParameter(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY + "," + Constants.CONFIGURATORS_CATEGORY + "," + Constants.ROUTERS_CATEGORY)); Invoker invoker = cluster.join(directory); // 向本地注册表,注册消费者 ProviderConsumerRegTable.registerConsuemr(invoker, url, subscribeUrl, directory); return invoker;}

DubboProtocol

根据提供者的url,创建了到服务端的客户端连接,并且封装到了DubboInvoker里。

public 
Invoker
refer(Class
serviceType, URL url) throws RpcException { // create rpc invoker. DubboInvoker
invoker = new DubboInvoker
(serviceType, url, getClients(url), invokers); invokers.add(invoker); return invoker;}/** * 连接远程服务提供者的客户端 * * @param url * @return */private ExchangeClient[] getClients(URL url) { // whether to share connection boolean service_share_connect = false; int connections = url.getParameter(Constants.CONNECTIONS_KEY, 0); // 配置连接数为0,就使用共享连接, // if not configured, connection is shared, otherwise, one connection for one service if (connections == 0) { service_share_connect = true; connections = 1; } ExchangeClient[] clients = new ExchangeClient[connections]; for (int i = 0; i < clients.length; i++) { if (service_share_connect) { clients[i] = getSharedClient(url); } else { clients[i] = initClient(url); } } return clients;}/** * Get shared connection */private ExchangeClient getSharedClient(URL url) { String key = url.getAddress(); ReferenceCountExchangeClient client = referenceClientMap.get(key); if (client != null) { if (!client.isClosed()) { // 计数+1 client.incrementAndGetCount(); return client; } else { referenceClientMap.remove(key); } } synchronized (key.intern()) { ExchangeClient exchangeClient = initClient(url); client = new ReferenceCountExchangeClient(exchangeClient, ghostClientMap); referenceClientMap.put(key, client); ghostClientMap.remove(key); return client; }}/** * Create new connection */private ExchangeClient initClient(URL url) { // client type setting. // 配置的Transporter的扩展实现,模式为netty String str = url.getParameter(Constants.CLIENT_KEY, url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_CLIENT)); // 设置编码器默认为DubboCountCodec,Dubbo SPI 自适应机制会根据这个key找到真正的实现 url = url.addParameter(Constants.CODEC_KEY, DubboCodec.NAME); // enable heartbeat by default url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT)); // BIO is not allowed since it has severe performance issue. // 是否是支持的Transporter的扩展实现 if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) { throw new RpcException("Unsupported client type: " + str + "," + " supported client type is " + StringUtils.join(ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions(), " ")); } ExchangeClient client; try { // connection should be lazy if (url.getParameter(Constants.LAZY_CONNECT_KEY, false)) { client = new LazyConnectExchangeClient(url, requestHandler); } else { client = Exchangers.connect(url, requestHandler); } } catch (RemotingException e) { throw new RpcException("Fail to create remoting client for service(" + url + "): " + e.getMessage(), e); } return client;}

附录

参照:

转载于:https://my.oschina.net/cregu/blog/2223340

你可能感兴趣的文章
创建一个最简单的Linux随机启动服务
查看>>
ibatis中使用like模糊查询
查看>>
Scrum三头猪
查看>>
mysql之视图
查看>>
用PHP语言做网站常见漏洞有哪些?
查看>>
项目管理学习笔记之二.工作分解
查看>>
奇异值分解(We Recommend a Singular Value Decomposition)
查看>>
一个单元测试 学习 aysnc await
查看>>
Linux驱动总结3- unlocked_ioctl和堵塞(waitqueue)读写函数的实现 【转】
查看>>
iOS开发网络篇—HTTP协议
查看>>
jboss7 添加虚拟目录 上传文件路径
查看>>
poj 2513 Colored Sticks(欧拉路径+并检查集合+特里)
查看>>
在eclipse中建立lua开发环境
查看>>
CRT/LCD/VGA Information and Timing
查看>>
C# PPT 为形状设置三维效果
查看>>
Android DecorView浅析
查看>>
EF(Entity Framework)系统学习系列
查看>>
C 双向链表
查看>>
hdu 5452(树链刨分)
查看>>
Java之IO流总结
查看>>