前言
上篇文章《Dubbo之服务暴露》分析 Dubbo 服务是如何暴露的,本文接着分析 Dubbo 服务的消费流程。主要从以下几个方面进行分析:注册中心的暴露;通过注册中心进行服务消费通知;直连服务进行消费。
服务消费端启动时,将自身的信息注册到注册中心的目录,同时还订阅服务提供方的目录,当服务提供方的 URL 发生更改时,实时获取新的数据。
服务消费端流程
下面是一个服务消费的流程图:
上图中可以看到,服务消费的流程与服务暴露的流程有点类似逆向的。同样,Dubbo 服务也是分为两个大步骤:第一步就是将远程服务通过Protocol
转换成Invoker
(概念在上篇文章中有解释)。第二步通过动态代理将Invoker
转换成消费服务需要的接口。
org.apache.dubbo.config.ReferenceConfig
类是ReferenceBean
的父类,与生产端服务的ServiceBean
一样,存放着解析出来的 XML 和注解信息。类关系如下:
服务初始化中转换的入口
当我们消费端调用本地接口就能实现远程服务的调用,这是怎么实现的呢?根据上面的流程图,来分析消费原理。
在消费端进行初始化时ReferenceConfig#init
,会执行ReferenceConfig#createProxy
来完成这一系列操作。以下为ReferenceConfig#createProxy
主要的代码部分:
1 | private T createProxy(Map<String, String> map) { |
上面转换的过程中,主要可概括为:先分为本地引用和远程引用两类。本地就是以 inJvm 协议的获取本地服务,这不做过多说明;远程引用分为直连服务和通过注册中心。注册中心分为单注册中心和多注册中心的情况,单注册中心好解决,直接使用即可,多注册中心时,将转换后的 Invoker 合并成一个 Invoker。最后通过动态代理将 Invoker 转换成本地接口代理。
获取 Invoker 实例
由于本地服务时直接从缓存中获取,这里就注册中心的消费进行分析,上面代码片段中使用的是REF_PROTOCOL.refer
进行转换,该方法代码:
1 | public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException { |
上面主要是获取服务消费的注册中心实例和进行服务分组,最后调用doRefer
方法进行转换工作,以下为doRefer
的代码:
1 | private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) { |
上面实现主要是完成创建 RegistryDirectory 对象,将消费服务元数据注册到注册中心,通过 RegistryDirectory 对象里的信息,实现服务提供端,动态配置及路由的订阅相关功能。
RegistryDirectory 这个类实现了 NotifyListener 这个通知监听接口,当订阅的服务,配置或路由发生变化时,会接收到通知,进行相应改变:
1 | public synchronized void notify(List<URL> urls) { |
RegistryDirectory#notify
里面最后会刷新 Invoker 进行重新加载,下面是核心代码的实现:
1 | private void refreshOverrideAndInvoker(List<URL> urls) { |
获取刷新前后的 Invokers,将新的 Invokers 重新缓存起来,通过对比,销毁无用的 Invoker。
上面将 URL 转换 Invoker 是在RegistryDirectory#toInvokers
中进行。
1 | private Map<String, Invoker<T>> toInvokers(List<URL> urls) { |
总结
通过《Dubbo之服务暴露》和本文两篇文章对 Dubbo 服务暴露和服务消费原理的了解。我们可以看到,不管是暴露还是消费,Dubbo 都是以 Invoker 为数据交换主体进行,通过对 Invoker 发起调用,实现一个远程或本地的实现。