dubbo服务暴露

前期准备

<dubbo:service/> 服务配置,用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心。
eg、<dubbo:service ref="demoService" interface="com.xxx.xxx.provider.DemoService" />

<dubbo:reference/> 引用服务配置,用于创建一个远程服务代理,一个引用可以指向多个注册中心。
eg、<dubbo:reference id="demoService" interface="com.xxx.xxx.provider.DemoService" />

<dubbo:protocol/> 协议配置,用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受。
eg、<dubbo:protocol name="dubbo" port="20880" />

<dubbo:application/> 应用配置,用于配置当前应用信息,不管该应用是提供者还是消费者。
eg、<dubbo:application name="provider" />

<dubbo:module/> 模块配置,用于配置当前模块信息,可选。
<dubbo:registry/> 注册中心配置,用于配置连接注册中心相关信息。
eg、<dubbo:registry address="zookeeper://192.168.2.249:2181" />

<dubbo:monitor/> 监控中心配置,用于配置连接监控中心相关信息,可选。
<dubbo:provider/> 提供方的缺省值,当ProtocolConfig和ServiceConfig某属性没有配置时,采用此缺省值,可选。
<dubbo:consumer/> 消费方缺省配置,当ReferenceConfig某属性没有配置时,采用此缺省值,可选。
<dubbo:method/> 方法配置,用于ServiceConfig和ReferenceConfig指定方法级的配置信息。
<dubbo:argument/> 用于指定方法参数配置。

Invoker URL ServiceBean

URL 之于 Dubbo,犹如水之于鱼,非常重要。

在 Dubbo 中,Invoker 是一个非常重要的模型。在服务提供端,以及服务引用端均会出现 Invoker。Dubbo 官方文档中对 Invoker 进行了说明,这里引用一下。

Invoker 是实体域,它是 Dubbo 的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起 invoke 调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。

1.概览

image

http://dubbo.apache.org/zh-cn/docs/dev/implementation.html

<dubbo:service/> → ServiceConfig→Invoker→ Exporter->启动server打开端口->注册

1.dubbo在什么时候进行服务暴露

[图片上传失败...(image-aaadb7-1562576327193)]

[图片上传失败...(image-ff9460-1562576327192)]

导出时机:
afterPropertiesSet

onApplicationEvent

为什么要延迟暴露

dubbo服务导出到那里?

导出了什么东西

怎么导出的

2.服务暴露过程
  • 1.检查准备环境配置
  • 2.加载注册中心
  • 3.暴露本地服务
  • 4.暴露远程服务
  • 5.注册

导出的入口
org.apache.dubbo.config.ServiceConfig#export

  1. 检测 <dubbo:service> 标签的 interface 属性合法性,不合法则抛出异常
  2. 检测 ProviderConfig、ApplicationConfig 等核心配置类对象是否为空,若为空,则尝试从其他配置类对象中获取相应的实例。
  3. 检测并处理泛化服务和普通服务类(扩展泛化调用)
  4. 检测本地存根配置,并进行相应的处理(解释存根)
    image
  5. 对 ApplicationConfig、RegistryConfig 等配置类进行检测,为空则尝试创建,若无法创建则抛出异常

检查配置举个例子 protocol

如果为空就set,然后增加属性

[图片上传失败...(image-819df9-1562576327192)]

  • 2.加载注册中心

[图片上传失败...(image-10b9e0-1562576327192)]

[图片上传失败...(image-3c064c-1562576327192)]

org.apache.dubbo.config.AbstractInterfaceConfig#loadRegistries的registries什么时候注入的?提出问题
org.springframework.beans.factory.BeanFactoryUtils#beansOfTypeIncludingAncestors(org.springframework.beans.factory.ListableBeanFactory, java.lang.Class<T>, boolean, boolean)
这里获取默认的配置 扩展IOC

双注册中心
haunt 资料
https://tech.youzan.com/haunt-youzan-service-discovery/

org.apache.dubbo.config.ServiceConfig#doExportUrlsFor1Protocol

1.将一些信息,比如版本、时间戳、方法名以及各种配置对象的字段信息放入到 map 中,map 中的内容将作为 URL 的查询字符串。构建好 map 后,紧接着是获取上下文路径、主机名以及端口号等信息。最后将 map 和主机名等数据传给 URL 构造方法创建 URL 对象。

[图片上传失败...(image-70bad3-1562576327192)]

3.暴露本地服务org.apache.dubbo.config.ServiceConfig#exportLocal

先看一下成员变量。使用spi

[图片上传失败...(image-53fddf-1562576327192)]

[图片上传失败...(image-d81aee-1562576327192)]

创建invoker的过程

[图片上传失败...(image-47e326-1562576327192)]

生成的protocol code

package org.apache.dubbo.rpc;
import org.apache.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
    public void destroy() {
        throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }
    public int getDefaultPort() {
        throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }
    public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        org.apache.dubbo.common.URL url = arg1;
        String extName = (url.getProtocol() == null ? "dubbo": url.getProtocol());
        if (extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.refer(arg0, arg1);
    }
    public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
        if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
        if (arg0.getUrl() == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
        org.apache.dubbo.common.URL url = arg0.getUrl();
        String extName = (url.getProtocol() == null ? "dubbo": url.getProtocol());
        if (extName == null) throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.export(arg0);
    }
}

String extName = (url.getProtocol() == null ? "dubbo": url.getProtocol());
org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);

最后得到
org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol

[图片上传失败...(image-d3033f-1562576327192)]

回忆getExtension的时候,对Protocol包装又包装。

build一个过滤链,启动一个服务质量监控服务器,增加一个监听者。

[图片上传失败...(image-93aad6-1562576327192)]

为什么要有本地暴露

本地调用使用了 injvm 协议,是一个伪协议,它不开启端口,不发起远程调用,只在 JVM 内直接关联,但执行 Dubbo 的 Filter 链。

http://dubbo.apache.org/zh-cn/docs/user/demos/local-call.html

org.apache.dubbo.registry.integration.RegistryProtocol#doLocalExport

org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#openServer

[图片上传失败...(image-ffbf2d-1562576327192)]

[图片上传失败...(image-1fea4f-1562576327192)]

org.apache.dubbo.rpc.Protocol#export 远程暴露

org.apache.dubbo.registry.integration.RegistryProtocol#export

远程暴露第一步 交给具体的协议去暴露本地端口

org.apache.dubbo.registry.integration.RegistryProtocol#doLocalExport

→org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#export(缓存exporter)

→org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#openServer(缓存server)

→org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol#createServer(给url增加一些属性)

  ->org.apache.dubbo.remoting.exchange.Exchangers#bind(org.apache.dubbo.common.URL, org.apache.dubbo.remoting.exchange.ExchangeHandler)(根据type获取对应的exchanger)

     ->org.apache.dubbo.remoting.Transporters#bind(org.apache.dubbo.common.URL, org.apache.dubbo.remoting.ChannelHandler...)(门面模式,具体交给netty去做)

        ->org.apache.dubbo.remoting.transport.netty4.NettyServer#doOpen(真正启动server的地方)

[图片上传失败...(image-498383-1562576327192)]

第二步-注册

获取注册中心

org.apache.dubbo.registry.support.AbstractRegistryFactory#getRegistry

→org.apache.dubbo.registry.etcd.EtcdRegistryFactory#createRegistry

→org.apache.dubbo.remoting.etcd.jetcd.JEtcdTransporter#connect

[图片上传失败...(image-c652f9-1562576327192)]

org.apache.dubbo.remoting.etcd.support.AbstractEtcdClient#create

[图片上传失败...(image-3893ab-1562576327192)]

org.apache.dubbo.remoting.etcd.jetcd.JEtcdClientWrapper#createPersistent

[图片上传失败...(image-71c6f8-1562576327192)]

模板方法

重点是把dubbo的url转换成etcd的节点

为啥注册中心挂了,服务还能继续通信?

com.alibaba.dubbo.registry.RegistryService#subscribe

最后。官网的说明

URL举例

dubbo://172.17.48.52:20880/com.alibaba.dubbo.demo.DemoService?anyhost=true&application=demo-provider&dubbo=2.0.2&generic=false&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello

服务提供者暴露一个服务的详细过程

image

上图是服务提供者暴露服务的主过程:

首先 ServiceConfig 类拿到对外提供服务的实际类 ref(如:HelloWorldImpl),然后通过 ProxyFactory 类的 getInvoker 方法使用 ref 生成一个 AbstractProxyInvoker 实例,到这一步就完成具体服务到 Invoker的转化。接下来就是 Invoker 转换到 Exporter 的过程。

Dubbo 处理服务暴露的关键就在 Invoker 转换到 Exporter 的过程,上图中的红色部分。下面我们以 Dubbo 和 RMI 这两种典型协议的实现来进行说明:

Dubbo 的实现

Dubbo 协议的 Invoker 转为 Exporter 发生在 DubboProtocol 类的 export 方法,它主要是打开 socket 侦听服务,并接收客户端发来的各种请求,通讯细节由 Dubbo 自己实现。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,978评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,954评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,623评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,324评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,390评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,741评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,892评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,655评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,104评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,569评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,254评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,834评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,725评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,950评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,260评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,446评论 2 348

推荐阅读更多精彩内容

  • 在Spring将xml中的各个标签解析成一个个BeanDefinition之后,接下来就是根据BeanDefini...
    spilledyear阅读 952评论 0 5
  • 笔记简述何所谓服务暴露,其实就是服务提供方把自己的服务提供出来,使得其他服务使用方能够跨网络(本地就不需要跨网络)...
    jwfy阅读 1,273评论 0 2
  • 笔记简述Dubbo服务暴露之前分为了两小节Dubbo 服务暴露 源码学习(上)(三) 和Dubbo 服务暴露 源码...
    jwfy阅读 884评论 1 3
  • 作为分布式框架,最核心的功能无非是服务的暴露和服务的引用,今天我们先说服务的暴露。 我们先从暴露服务配置说起 我们...
    数齐阅读 10,397评论 2 12
  • 先看官网两张图【引用来自官网】:image.png 官网说明: 1.首先 ReferenceConfig 类的 i...
    致虑阅读 1,021评论 0 2