本文转载自微信公众号《大禹仙人》,作者:大禹仙人。转载本文请联系大禹仙人公众号。一、前言前两篇分别介绍了Dubbo的介绍和Dubbo的服务暴露。有两个时间可以做到这一点。第一种是在Spring容器调用ReferenceBean的afterPropertiesSet方法时引用service,第二种是将ReferenceBean对应的service注入其他类时引用。这两个引文服务的时间差异是第一个是给饥饿的人用的,第二个是给懒惰的人用的。你有没有提到饥饿的人和懒惰的人?顺便大家回忆了一波单例模式。Dubbo默认使用Lazy引用服务。如果需要使用饿了么中国风,可以通过配置的init属性开启。引入服务有三种方式:第一种是引用本地(JVM)服务。在上一篇文章中,我们在服务暴露中也说过,每个服务都会通过injvm协议暴露在本地,因为有服务端和消费者。在同一台机器上也是如此。这样直接使用本地调用,不需要使用远程调用,节省了网络开销。二是通过直连的方式来引用远程服务,网上基本用不到。一般我们平时自己测试用,直接写服务端的地址来调用。三是通过注册中心引用远程服务。消费者通过注册中心了解提供商的相关信息,进而介绍服务。不管是哪种引用方法,最终都会得到一个Invoker的实例。如果有多个注册中心和多个服务提供者,此时会得到一组Invoker实例。这时需要通过集群管理类Cluster将多个Invoker实例合并为一个实例。合并后的Invoker实例已经具备了调用本地或远程服务的能力。但是开发者本着不侵入用户业务代码的原则,所以此时框架还需要通过代理工厂类ProxyFactory生成服务接口的代理类,让代理类调用Invoker逻辑,避免Dubbo框架代码对业务代码的侵入。2、服务发现dubbo的服务发现是通过从注册中心订阅一个服务提供者,组装成一个URL,然后通过URL创建一个调用者来实现的服务。服务的引入和服务的暴露是一样的service,通过spring自定义标签机制解析生成相应的Bean。ProviderService对应ServiceBean的解析,ConsumerReference对应ReferenceBeandubbo的服务发现,由注册中心订阅服务提供者组装而成。URL,然后通过URL创建一个Invoker来实现。这里是入口,进去看ReferenceBeancreateLazyProxy,我们会看到目标资源DubboReferenceLazyInitTargetSource,在新建的地方点击,protected方法createObject调用getCallProxy,这个方法最后调用referenceConfig.get()点击进去,我们的方法输入的是ReferenceConfig类,而不是ReferenceBean。这是因为ReferenceConfig作为ReferenceBean的内部属性出现。Init()方法主要是通过Map设置各种参数。让我们看看其中一个名为createProxy的init方法。从名字我们也可以知道,大致意思就是创建一个代理对象。点进去看看是不是本地的,那就直接建一个本地的协议URL然后引入服务,就是refprotocol.refer。这个方法后面会分析,本地就不深入介绍了。就是去之前service暴露出来的exporterMap去获取service。如果它不是本地的,那么它一定是远程的。接下来判断是直接连接provider还是通过注册中心获取provider信息再连接provider。我们分析下配置url的情况。如果配置了url,不是直连地址,而是注册中心的地址。这其实就是整个过程。简单描述就是先检查配置,通过配置构建map,然后使用map构建url,然后在url上使用protocol,使用自适应扩展机制调用对应的protocol。参考获取相应的调用者。我给大家总结一张流程图,方便大家看的更清楚。3.服务引用Dubbo的服务引用其实就是为被引用的接口创建一个Proxy。这个Proxy的作用是执行refprotocol.refer(interfaceClass,url)创建的Invoker。当有多个服务提供者时,创建一个ClusterInvoker。Cluster是一个SPI扩展点,默认使用com.alibaba.dubbo.rpc.cluster.support.FailoverCluster。因此,将消费端服务调用的逻辑封装在refprotocol.refer(interfaceClass,url)创建的Invoker中获取注册。center实例,然后调用doRefer进行真正的refer。这里,它会向注册中心注册自己的信息,生成一个Invoker,在底层生成一个用于远程调用的invoker,然后通过cluster包装得到ClusterInvoker,所以一个service可能有多个provider,以及最后注册对应的监听器获取到Provider的信息后,就可以监听触发Protocol#refer了。调用哪个协议取决于URL协议。我们看下DubboProtocol内部的refer和connect最终会返回到HeaderExchangeClient中封装的NettyClient,最后getinvoker就是对这个client的封装,最终会返回一个Proxy4的代理对象。整个过程和看代码,刚开始可能会遇到很多新名词,但是仔细想想也不难,所以静下心来好好分析一下,其实很简单。其实就是通过各种配置参数和协议组装成对应的URL,然后通过自动适配对应的实现类来引入对应的服务和后续的调用。如果是硬编码地址直接连接,注册中心会向注册中心注册信息,然后订阅注册中心的相关信息,获取服务商的IP端口号等信息,通过netty连接,而底层会通过目录和集群的屏蔽和负载均衡处理,进行多个底层服务,得到代理对象Invoker,再通过动态代理封装得到代理类。决策层代理
