服务引入
目标
根据服务名去找到服务提供者的地址,以备后续进行调用,这里存在两种查找方式。
- 如果明确制定了(配置了url属性),那就去指定的注册中心地址,或指定的服务提供者地址去找(这种方式就是直连,不会经过路由策略),官网描述。
- 如果没有明确制定,那就从配置的注册中心去找服务提供者地址,注意,这里可能会配置多个注册中心(会经过路由策略)
过程分析
首先是通过xml配置服务的reference
服务引入具体体现在DubboNamespaceHandler中的init
方法,通过分析注册ReferenceBean来实现的服务引入
在ReferenceBean对象中真正引入是在调用get
方法得到实例对象的时候
真正的逻辑是在init()
方法中
在init
方法中会先取出接口的所有信息和自身的服务配置信息
1.org.apache.dubbo.config.ReferenceConfig#init
2.org.apache.dubbo.config.ReferenceConfig#createProxy
在createProxy
方法中会将接口和配置信息组装成一个url,通过refer
方法完成服务invoker对象的引入,这里会根据调用方式的不同用不同的方法处理,下面是普通调用方式的分析,通过注册中心拿到服务提供者并需要经过路由的过滤。
3.org.apache.dubbo.registry.integration.RegistryProtocol#refer
4.org.apache.dubbo.registry.integration.RegistryProtocol#doRefer
接着会在doRefer方法中完成四个重要的步骤
- 构造路由链
- 监听配置及服务节点
- 聚合得到的invoker对象
- 构造路由链
在下面的buildRouterChain方法中构造的路由链
在这个方法中会通过url信息得到对应的路由工厂,通过路由工厂实例化路由对象,这里会产生2类路由,3种路由对象
- TagRouterFactory工厂对象产生的TagRouter路由对象,属于标签路由(2.7之后出现)
- AppRouterFactory工厂对象产生的AppRouter路由对象,属于条件路由
- ServiceRouterFactory工厂对象产生的ServiceRouter路由对象,属于条件路由
TagRouter是继承自AbstractRouter的,并无特别的地方,但是AppRouter和ServiceRouter继承自ListenableRouter,在这两个对象调用构造方法时会调用父类的构造器,会调用init
方法
在init
方法中会监听各自的路由节点
- 监听配置及服务节点
在subscribe
方法中完成的监听
监听自身的服务配置节点和监听服务提供者节点,还会为了兼容老版本的注册中心监听三个目录
- 聚合得到的invoker对象
最后通过cluster的join方法将所有的invoker对象聚合成为一个invoker对象
最后会返回一个invoker的代理对象,这个代理对象就是我们通过getBean
方法拿到的bean对象
服务引入总结
找到了服务提供者地址之后,可能会找出多个,在没有任何其他比如说路由的条件下,那么找出来的提供者地址对于消费者来说都是可用的,但是服务消费端它需要的是一个实现了接口的代理类,注意这里不是真实的示例类的实例,所以这个代理类其中有一个最重要的任务就是要去进行远程方法调用,那么这个代理类就可以理解为一个Invoker,这个Invoker还需要从多个地址中负载均衡出来某一个地址,最终去调用这个地址的相对应的服务。
当然,如果消费者再运行期间,路由策略是可以调整的,所以,消费者在启动期间是需要去监听路由策略是否发生了变化得,同时,对于消费者引入服务的参数也是可能发生变化的,比如timeout,所以也需要监听。
- 从注册中心找到所有服务提供者的地址
- 包装所有服务提供者的地址在一个对象内
- 注册监听器监听路由策略的变化、服务提供者地址的变化、服务调用相关信息的变化
需要注意的是再服务引入的过程中没有进行路由过滤的操作,而是再调用服务的时候才进行了过滤。
监听对象
- 服务提供者
- 条件路由
- 标签路由
- 黑白名单路由
- 服务配置信息