一、Dubbo服务暴露过程
下图是Dubbo官网的一个服务提供者暴露服务的主过程:上图是服务提供者暴露服务的主过程:
首先 ServiceConfig
类拿到对外提供服务的实际类 ref(如:HelloWorldImpl),然后通过 ProxyFactory
类的 getInvoker
方法使用 ref 生成一个 AbstractProxyInvoker
实例,到这一步就完成具体服务到 Invoker
的转化。接下来就是 Invoker
转换到 Exporter
的过程。
Dubbo 处理服务暴露的关键就在 Invoker
转换到 Exporter
的过程,上图中的红色部分。下面我们以 Dubbo 和 RMI 这两种典型协议的实现来进行说明:
Dubbo 的实现
Dubbo 协议的 Invoker
转为 Exporter
发生在 DubboProtocol
类的 export
方法,它主要是打开 socket 侦听服务,并接收客户端发来的各种请求,通讯细节由 Dubbo 自己实现。
RMI 的实现
RMI 协议的 Invoker
转为 Exporter
发生在 RmiProtocol
类的 export
方法,它通过 Spring 或 Dubbo 或 JDK 来实现 RMI 服务,通讯细节这一块由 JDK 底层来实现,这就省了不少工作量。
解析服务
在ServiceConfig.export()或ReferenceConfig.get()初始化时,将Bean对象转换暴露服务或请求服务的URL,所有Bean属性转成URL的参数。
然后将URL传给Protocol扩展点,基于扩展点的Adaptive机制,根据URL的协议头,进行不同协议的服务暴露或引用。
url参数列只有group,interface,version是服务的匹配条件,三者决定是不是同一个服务,其它配置项均为调优和治理参数
暴露服务
有注册中心配置:<dubbo:registry address="zookeeper://10.20.153.10:2181" />
ServiceConfig解析出的URL的格式为:
registry://registry-host/com.alibaba.dubbo.registry.RegistryService?export=URL.encode("dubbo://service-host/com.foo.FooService?version=1.0.0")
1)基于扩展点的Adaptive机制,通过URL的"registry://"协议头识别,就会调用RegistryProtocol的export()方法,将export参数中的提供者URL,先注册到注册中心,再重新传给Protocol扩展点进行暴露:
dubbo://service-host/com.foo.FooService?version=1.0.0
2)基于扩展点的Adaptive机制,通过提供者URL的"dubbo://"协议头识别,就会调用DubboProtocol的export()方法,打开服务端口。
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
Exporter<?> exporter = protocol.export(invoker);
具体服务àInvoker àExporter Exporter是负载打开服务端口等待请求。
引用服务
注册中心配置:<dubbo:registry address="zookeeper://10.20.153.10:2181" />
ReferenceConfig解析出的URL的格式为:
registry://registry-host/com.alibaba.dubbo.registry.RegistryService?refer=URL.encode("consumer://consumer-host/com.foo.FooService?version=1.0.0")
基于扩展点的Adaptive机制,通过URL的"registry://"协议头识别,就会调用RegistryProtocol的refer()方法,基于refer参数中的条件,查询提供者URL,如:
dubbo://service-host/com.foo.FooService?version=1.0.0
基于扩展点的Adaptive机制,通过提供者URL的"dubbo://"协议头识别,就会调用DubboProtocol的refer()方法,得到提供者引用。
然后RegistryProtocol将多个提供者引用,通过Cluster扩展点,伪装成单个提供者引用返回。
invoker = refprotocol.refer(interfaceClass, urls.get(0));
(T) proxyFactory.getProxy(invoker);
拦截服务
基于ProtocolFilterWrapper类,将所有Filter组装成链,在链的最后一节调用真实的引用。
基于ProtocolListenerWrapper类,将所有InvokerListener和ExporterListener组装集合,在暴露和引用前后,进行回调。
包括监控在内,所有附加功能,全部通过Filter拦截实现。
- 用户自定义filter默认在内置filter之后。
- 特殊值default,表示缺省扩展点插入的位置。
-
- 比如:filter="xxx,default,yyy",表示xxx在缺省filter之前,yyy在缺省filter之后。
- 特殊符号-,表示剔除。
-
- 比如:filter="-foo1",剔除添加缺省扩展点foo1。
- 比如:filter="-default",剔除添加所有缺省扩展点。
- provider和service同时配置的filter时,累加所有filter,而不是覆盖。
-
- 比如:<dubbo:provider filter="xxx,yyy"/>和<dubbo:service filter="aaa,bbb" />,则xxx,yyy,aaa,bbb均会生效。
- 如果要覆盖,需配置:<dubbo:service filter="-xxx,-yyy,aaa,bbb" />