大致流程

Provider将服务暴露出来并且注册到注册中心,而Consumer通过注册中心获取Provider的信息,之后将自己封装成一个调用类去与Provider进行交互。

首先需要将所有调用转化为Dubbo中我们熟悉的Invoker,再通过代理类去远程获取服务。

大致流程如下:

服务引用策略

服务的引用和服务的暴露原理相似,都是Spring自定义标签机制解析生成对应的Bean,在之前服务暴露使用到的Provider Service使用的是ServiceBean,而Comsumer Reference使用的ReferenceBean

服务暴露是在SpringIOC容器完成刷新后开始暴露的,而服务的引入则分为两种,分别是饿汉式懒汉式

饿汉式是通过实现Spring的InitializingBean接口中的afterPropertiesSet()实现的,通过上图中ReferenceBean的实现也可以获知,而容器通过调用ReferenceBean中的afterPropertiesSet()时引入服务。

懒汉式是只有某个服务被注入到其他类时才开始启动引入流程。

默认情况下,Dubbo会使用懒汉式引入策略,如果需要使用饿汉式,需要在<dubbo:reference/>中配置init开启。

并且通过上图我们还可以看到ReferenceBean还实现了FactoryBean,Dubbo通过这个实现来进行懒汉式引用服务。

服务引用的三种方式

服务引用分为三种方式:

  • 本地引入
  • 直接使用连接引入远程服务
  • 通过注册中心引入远程服务

本地引入的基础是之前介绍过的本地暴露,某个服务端可能同时是Provider又是Comsumer,并且可能会自己调用本地的服务,这种情况下不需要进行网络调用,所以引入了本地引用,来避免不必要的网络开销。

服务引入时,第一步做的就是在本地中查找是否有可用的本地服务。

直连引入服务,这种方式不需要注册中心的支持,绕过了注册中心,直接通过Url来引用远程服务,具体实现是在Comsumer中写死Provider的具体地址,然后在调用时直接连接即可,一般用于测试,如果大量服务之间都使用直连引入,那么服务集群之间的关系将错综复杂,变得那以维护和管理。

注册中心引入服务,Comsumer通过注册中心获取Provider的相关信息,然后进行服务的引入,其中还涉及到多注册中心,服务集群时的负载均衡,以及容错机制。

服务引入流程解析

前提:服务引入选择默认的懒汉式引入策略并且使用注册中心引入服务。

服务引入的入口是ReferenceBean.getObject()

然后会调用父类ReferenceConfig.get()

进入init()方法,前面的一大串代码就是做if else判断的配置检查并且将配置放入map,构建完毕后的map如下:

再进入createProxy()方法

如果是本地引入的话,会构建一个本地引入的URL然后进行服务的引入,即图示中的refprotocol.refer()

不是本地引入,那么就是远程引入了,接下来需要判断的是点对点直连provider还是通过注册中心拿到provider信息再进行连接。

以下是点对点直连:

以下是通过注册中心连接:

最终拼接出来的URL如下图所示:

方法最后通过代理封装invoker返回代理实现。

上图就是整个服务引用流程。

但是还有很多细节,比如如何从注册中心获得Provider,invoker内部结构是怎么样的?

在上面URL的截图中,我们可以看到此时的协议是registry,因此会调用RegistryPotocol.refer()

获取注册中心实例,之后调用doRefer()

RegistryDirectory类是实现了NotifyListener接口的,注册中心的监听功能就此而来。

public class RegistryDirectory<T> extends AbstractDirectory<T> implements NotifyListener {}

public interface NotifyListener {
    void notify(List<URL> var1);
}

向注册中心注册自身信息之后,会向注册中心订阅providersconfiguratorsrouters节点信息。订阅之后RegistryDirectory会收到这几个节点的信息,并触发DubboInvoker的生成,即用于远程调用的invoker。

再通过cluster封装得到invoker,因此一个服务可能有多个提供者,最终在ProviderConsumerRegTable记录这些信息,然后返回invoker。

拿到Provider的信息之后就会通过监听触发DubboProtocol.refer()

重点在getClients()方法中,这个方法是用于获取客户端实例的,实例类型为ExchangeClient[],底层依赖Netty进行通讯,并且是默认共享连接的。

再进入initClient()方法中看看初始化客户端的具体细节:

最后返回的(ExchangeClient) client封装的是NettyClient

最后得到的Invoker如下,其中记录到了许多信息:

最后调用return proxyFactory.getProxy(this.invoker);将代理对象返回。

以下是整个服务引用的流程图:

总结

首先是通过配置构建URL,再通过协议头自适应拓展得到具体的实现类进行服务引入,之后消费者向注册中心注册自己的信息,然后订阅相关信息,得到远程服务提供者的信息,最后通过NettyClient进行连接通讯。

还会通过DirectoryCluster进行多个服务提供者的合并、屏蔽、容错以及负载均衡,最终将封装好的可执行体Invoker通过动态代理封装得到代理对象返回。

以上就是java开发分布式服务框架Dubbo服务引用详解的详细内容,更多关于Dubbo服务引用的资料请关注悠悠之家其它相关文章!

点赞(52)

评论列表共有 0 条评论

立即
投稿
返回
顶部