dubbo源码分析8(服务消费者之生成代理对象)

  前面几篇博客,说了很多dubbo服务提供者相关的流程;

  复习一下:首先服务提供者去暴露服务接口数据到注册中心,然后本地启动netty服务端监听是否有消费者的请求,现在我们可以看看消费者端是怎么从注册中心获取指定的接口信息, 然后访问netty服务端,就行了;

  提前须知:要提前了解spring的ioc容器初始化的过程以及调用ioc容器的getBean的逻辑,这个不是我们的重点

 

1 准备工作

  我们先大概看看服务消费者大概做了些什么事情,打开消费者端的demo,下图所示,首先是初始化spring的ioc容器,然后从容器中获取实例bean, 然后调用该bean的方法

 

  结合我们知道的spring的知识,我们就大胆的猜测一下,在spring的ioc初始化的过程中,会解析我们配置在xml文件中<dubbo:reference id="xxx" interface="xxx"/>,解析出来的对象放在ioc容器中,下图所示,很明显当前服务的BeanDefinition中封装的是ReferenceBean对象,ReferenceBean封装了该服务的信息;

  这里消费者端初始化ioc容器的时候,和服务提供者一样,都是在DubboBootstrap的start方法开始发车,这个start方法里面会调用exportServices()方法暴露服务和referServices()引用服务,因为一个服务既可以是服务提供者,同时也可以是服务消费者,这个不难理解吧!比如A->B->C, B服务对A来说是服务提供者, 对C来说是服务消费者

 

  然后就是spring的逻辑了,在从ioc获取对象(也就是调用getBean方法)的时候,会判断这个对象ReferenceBean有没有实现FactoryBean接口,有的话,就调用FactoryBean的getObject方法

 

  刚好我们去看看ReferenceBean类,巧了( ̄o ̄) . z Z,刚好实现了FactoryBean接口,于是就会调用下图的getObject()方法

 

 

  总结一下,服务消费者就干了三件事:

  (1)启动ioc容器进行初始化,初始化过程中对dubbo的配置文件进行解析

    (2)从ioc容器获取bean的时候,调用getBean方法的时候,会判断当前的Bean是否实现了FactoryBean接口,有的话,就调用getObject方法生成代理对象,并放入ioc容器中

  (3)调用代理对象的方法,这个方法内部封装了远程调用的细节,返回调用结果;

 

2.生成代理对象

  这里默认大家都对spring的ioc容器的启动已经很熟悉了,就不再过多的描述,我们就看看是怎么生成代理对象的;

  我们就从ReferenceBean的getObject方法开始出发,连续截图三张,我们可以看到调用了父类的ReferenceConfig的get()方法, 再之后就是调用init()方法进行初始化操作

 

  这个init方法很长, 我们等下看看调用createProxy(xxx)方法的逻辑

 

 

 

  2.1 创建代理对象

    这个init方法百分之九十的代码都是设置参数到map里面,然后再根据这个map创建代理对象

 

  下面都是createProxy方法内部比较重要的部分,总结一下其实就是干了几件事,首先就是判断引用的服务是本地注册还是远程注册, 如果是远程注册就继续判断有几个注册中心,如果只有一个注册中心的话,就去那个注册中心获取服务数据转为一个invoker就好了;

  如果是多个注册中心,就将每个注册中心中的该服务信息多转为invoker, 再用cluster将多个invoker合并成一个统一的invoker;

  最终就是调用代理工厂proxyFactory将invoker生成代理对象;

 

 

 

 

  最终的根据代理工厂将invoker生成代理对象

 

 

  现在基本流程我们知道了,首先看看是否有多个注册中心,因为一个服务可以同时注册到多个注册中心,这里会从多个注册中心中获取相同名字的服务, 然后再将这些服务合并成一个invoker,然后就是根据最后生成的invoker生成代理类

  接下来我们继续看看REF_PROTOCOL.refer(xxx)生成invoker的逻辑,还有FROXY_FACTORY.getProxy(invoker)生成代理类,理解了这两个逻辑,就ok了;

  

  2.2 REF_PROTOCOL.refer(xxx)生成invoker

  由于现在只有一个注册中心,我们从这里进入开始看看怎么生成invoker的逻辑

 

  首先获取到注册中心实例,根据我们的消费者端的信息,去注册中心里创建consumer节点,然后接下来就是订阅providers、configurators、routers 等节点数据,只要是这几个节点有数据变化,就会通知到消费者端

 

 

  其实到这里就已经很清晰了, 不过在上图的第3步,就是用一个接口可能是集群部署的嘛,然后都注册到同一个注册中心中,我们需要将获取到的这个接口的多个服务提供者,然后又给聚合成一个invoker(其实这里的directory比较形象,中文意思是目录,这个目录下可能有多个服务提供者的呀)

 

  3.FROXY_FACTORY.getProxy(invoker)生成代理对象

  在上面我们已经从所有注册中心获取了所有实现了该接口的服务,最后合并成了一个invoker,然后就是根据这个invoker生成代理对象

  在getProxy()方法里面,其实就是判断当前服务接口是不是一个泛化接口(可以去了解一下dubbo的泛化,就是另外一种调用接口的方式而已,可以不提供服务接口),如果是的话,就做特殊处理,否则就把代理对象直接返回

  这里很明显就是直接返回代理对象

 

  当代理对象生成出来了之后,后续的就跟dubbo没啥关系了, 就是spring的内容,将生成的代理对象放到ioc容器中,并该接口的全名称对应起来,只要是下次我们再去获取这个实例的时候,就直接从ioc容器中获取了

  下图所示,可以看到是一个代理对象

 

  可以看到最终的ioc容器中已经有个这个代理对象了

 

 

 

  4.总结

  服务消费者的逻辑会比较多,现在首先会根据你要调用的这个接口,去多个注册中心看看,而且每个注册中心相同的一个服务A还有可能有多个,我们最终就多个服务A给拼接成一个invoker

  然后我们再使用代理工厂将这个invoker生成一个代理对象,并且和该服务接口名称对应起来放到spring的ioc容器中,下次再去获取这个接口的服务的时候,就能获取到这个代理对象了,这个代理对象中肯定是封装了netty远程调用的逻辑

  下一篇我们看看是怎么进行远程调用,怎么拿到接口调用的返回值

posted @ 2022-04-03 19:42  java小新人  阅读(494)  评论(0编辑  收藏  举报