源码分析Dubbo前置篇-寻找注册中心、服务提供者、服务消费者功能入口

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 本节主要阐述如下两个问题: Dubbo自定义标签实现。 dubbo通过Spring加载配置文件后,是如何触发注册中心、服务提供者、服务消费者按照Dubbo的设计执行相关的功能。 所谓的执行相关功能如下: 注册中心启动,监听消息提供者的注册服务、接收消息消费者的服务订阅(服务注册与发现机制)。

本节主要阐述如下两个问题:

  1. Dubbo自定义标签实现。
  2. dubbo通过Spring加载配置文件后,是如何触发注册中心、服务提供者、服务消费者按照Dubbo的设计执行相关的功能。

所谓的执行相关功能如下:

  • 注册中心启动,监听消息提供者的注册服务、接收消息消费者的服务订阅(服务注册与发现机制)。
  • 服务提供者向注册中心注册服务。
  • 服务消费者向注册中心订阅服务。

接下来从使用dubbo的角度,从配置文件入手:

1、Dubbo服务提供者的一般配置如下:

<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="uop" owner="uce"/>
<!-- 使用zookeeper注册中心暴露服务地址 -->
<dubbo:registry protocol="zookeeper" address="zookeeper://192.168.xx.xx:2181?backup=192.168.xx.xx:2182,192.168.xx.xx:2183" />
<!--dubbox中引入Kryo和FST这两种高效Java序列化实现,来逐步取代原生dubbo中的hessian2,如果使用kryo记得添加依赖 -->
<dubbo:protocol name="dubbo" serialization="kryo"  port="20990"  />
<!-- 定义服务提供者默认属性值 -->
<dubbo:provider timeout="5000" threadpool="fixed"  threads="100" accepts="1000" token="true"/>
<!-- 暴露服务接口 一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心-->
<!--Provider上尽量多配置Consumer端的属性,让Provider实现者一开始就思考Provider服务特点、服务质量的问题-->
<dubbo:service interface="com.yingjun.dubbox.api.UserService" ref="userService" />

   上面通过dubbo提供的dubbo:application、dubbo:registry、dubbo:protocol、dubbo:provider、dubbo:service分别定义dubbo应用程序名、注册中心、协议、服务提供者参数默认值、服务提供者,这些配置后面的实现原理是什么呢?是如何启动并发挥相关作用的呢?

2、Spring自定义标签即命令空间实现

dubbo自定义标签与命名空间其实现代码在模块dubbo-config中,其核心实现如下:

2.1 DubboNamespaceHandler

dubbo命名空间实现handler,其全路径:com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler,其源码实现如下:

public class DubboNamespaceHandler extends NamespaceHandlerSupport {

    static {
        Version.checkDuplicate(DubboNamespaceHandler.class);
    }

    @Override
    public void init() {
        registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
        registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
        registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
        registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
        registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
        registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
        registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
        registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
        registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
        registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
    }
}

从这里可以看出,dubbo自定义的标签主要包括:application、module、registry、monitor、provider、consumer、protocol、service、reference、annotation,其具体解析实现类主要包括:DubboBeanDefinitionParser(基于xml配置文件)、AnnotationBeanDefinitionParser(基于注解),下文会详细分析上述两个解析类的实现。

2.2 定义dubbo.xsd 文件

   在dubbo-config-spring模块下的 src/main/resouce/META-INF中分别定义dubbo.xsd、spring.handlers、spring.schemas。
   关于Spring如何新增命名空间与标签,在源码分析ElasticJob时已经详细介绍过,再这里就不做 过多重复,如需了解,请查看:https://blog.csdn.net/prestigeding/article/details/79751023

3、Bean解析机制(Spring基础知识)

我们应该知道,Spirng的配置支持xml配置文件与注解的方式,故Dubbo也支持两种配置方式,xml与注解方式。

3.1 xml配置方式解析

c

BeanDefinitionParser:Spring定义的bean解析器,要实现自定义标签,则需要实现该接口,然后通过NamespaceHandlerSupport将Bean定义解析器注册到Spring bean解析器中。从接口中可以看出,其终极目标就是将Element element(xml节点)解析成BeanDefinition,有关于Spring BeanDefinition,请参考:https://blog.csdn.net/prestigeding/article/details/80490206

DubboBeanDefinitionParser构造函数如下:

public DubboBeanDefinitionParser(Class<?> beanClass, boolean required) {
        this.beanClass = beanClass;
        this.required = required;
}
  • beanClass:该xml标签节点最终会被Spring实例化的类名。
  • required:该标签的ID是否必须。
标签名 类名
dubbo:application ApplicationConfig
dubbo:module ModuleConfig
dubbo:registry RegistryConfig
dubbo:monitor MonitorConfig
dubbo:provider ProviderConfig
dubbo:consumer ConsumerConfig
dubbo:protocol ProtocolConfig
dubbo:service ServiceBean
dubbo:reference ReferenceBean

注:包名:com.alibaba.dubbo.config

bean解析器的主要目的就是将上述标签,解析成对应的BeanDifinition,以便Spring构建上述类的实例。

本节不拷贝DubboBeanDefinitionParser根据xml定义的标签与属性转换成BeanDefinitionParser的每一行代码,本节只给出其大体关键点。

Step1:解析id属性,如果DubboBeanDefinitionParser对象的required属性为true,如果id为空,则根据如下规则构建一个id。

  • 如果name属性不为空,则取name的值,如果已存在,则为 name + 序号,例如 name,name1,name2。
  • 如果name属性为空,如果是dubbo:protocol标签,则取protocol属性,其他的则取interface属性,如果不为空,则取该值,但如果已存在,和name处理相同,在后面追加序号。
  • 如果第二步还未空,则取beanClass的名称,如果已存在,则追加序号。

Step2:根据不同的标签解析特殊属性。

  • dubbo:protocol,添加protocol属性(BeanDefinition)。
  • dubbo:service,添加ref属性。
  • dubbo:provider,嵌套解析,dubbo:provider标签有两个可选的子标签,dubbo:service、dubbo:parameter,这里需要嵌套解析dubbo:service标签。

知识点:dubbo:provider是配置服务提供者的默认参数,在dubbo spring配置文件中可以配置多个dubbo:provider,那dubbo:service标签如何选取一个合适的dubbo:provider作为其默认参数呢?有两种办法:

  1. 将dubbo:service标签直接声明在dubbo:provider方法
  2. 在dubbo:service中通过provider属性指定一个provider配置,如果不填,并且存在多个dubbo:provider配置,则会抛出错误。
  • dubbo:customer:解析嵌套标签,其原理与dubbo:provider解析一样。

Step3:解析标签,将属性与值填充到BeanDefinition的propertyValues中。最终返回BeanDefinition实例,供Spring实例化Bean。

上述已经解答了Dubbo自定义标签的解析实现,主要完成了ApplicationConfig、RegistryConfig、ServiceBean、ReferenceBean实例的初始化,那什么时候构建与注册中心的连接、服务提供者什么时候会向注册中心注册服务,服务消费者向注册中心订阅服务呢?

通过上述步骤,我们已经知道已经成功解析注册中心、服务提供者、服务消费者的配置元信息,并将其实例化,按照我们的思路,配置对象生成后,下一步应该是实现Dubbo服务的注册与发现机制,但代码中无法找到相关代码。

据我目前所掌握的知识,Spring在对象实例化,一般有两种方式来对Bean做一些定制化处理。

  1. 实现BeanPostProcessor Spring后置处理器,在Bean初始化前后执行相关操作。
  2. Bean实现InitializingBean接口(init-method)

浏览表格中所有Bean的声明,发现了两个类非常特殊:
20180528231944883

ServiceBean(服务提供者)与ReferenceBean(服务消费者)比较特殊,实现了Spring与Bean生命周期相关的接口。

  • InitializingBean,其声明的接口为afterPropertiesSet方法,顾名思义,就是在bean初始化所有属性之后调用。
  • DisposableBean:其声明的接口为destroy()方法,在Spring BeanFactory销毁一个单例实例之前调用。
  • ApplicationContextAware:其声明的接口为void setApplicationContext(ApplicationContext applicationContext),实现了该接口,Spring容器在初始化Bean时会调用该方法,注入ApplicationContext,已方便该实例可以直接调用applicationContext获取其他Bean。
  • ApplicationListener< ContextRefreshedEvent>:容器重新刷新时执行事件函数。
  • BeanNameAware:其声明的接口为:void setBeanName(String name),实现该接口的Bean,其实例可以获取该实例在BeanFactory的id或name。
  • FactoryBean:Spring初始化Bean的另外一种方式,例如dubbo:reference,需要返回的对象并不是ReferenceBean,而是要返回ref指定的代理类来执行业务操作,故这里使用FactoryBean非常合适,FactoryBean定义了如下三个方法:
  1. T getObject() throws Exception:获取需要返回的结果对象。
  2. Class<?> getObjectType():获取返回对象的类型。
  3. boolean isSingleton():返回是否是单例。

看到这里,不免有一点小激动,似乎已经摸到Dubbo服务注册与发现机制(Dubbo服务提供者、Dubbo服务消费者、注册中心的启动流程入口点了,下一步就是分析ServiceBean、ReferenceBean的实现原理,试图揭开Dubbo服务注册与发现机制,该部分内容将在下一篇中详细分析。

3.2 注解配置方式解析

注解配置方式的解析入口类:AnnotationBeanDefinitionParser,也是基于Spring注解解析逻辑,这部分在将在未来《Spring系列进阶篇-源码分析注解解析实现原理》中详细分析,目前暂未深究,读者朋友们,如果有兴趣,可以以AnnotationBeanDefinitionParser为入口,进行进一步的分析。

本节就讲解到这里了,下一篇将重点分析ServiceBean(服务提供者启动流程)。


原文发布时间为:2019-01-24
本文作者:丁威,《RocketMQ技术内幕》作者。
本文来自中间件兴趣圈,了解相关信息可以关注中间件兴趣圈

目录
相关文章
|
2月前
|
Dubbo 应用服务中间件 Apache
Dubbo 应用切换 ZooKeeper 注册中心实例,流量无损迁移
如果 Dubbo 应用使用 ZooKeeper 作为注册中心,现在需要切换到新的 ZooKeeper 实例,如何做到流量无损?
19 4
|
2月前
|
监控 Dubbo Java
dubbo学习三:springboot整合dubbo+zookeeper,并使用dubbo管理界面监控服务是否注册到zookeeper上。
这篇文章详细介绍了如何将Spring Boot与Dubbo和Zookeeper整合,并通过Dubbo管理界面监控服务注册情况。
100 0
dubbo学习三:springboot整合dubbo+zookeeper,并使用dubbo管理界面监控服务是否注册到zookeeper上。
|
4月前
|
JSON Dubbo Java
【Dubbo协议指南】揭秘高性能服务通信,选择最佳协议的终极攻略!
【8月更文挑战第24天】在分布式服务架构中,Apache Dubbo作为一款高性能的Java RPC框架,支持多种通信协议,包括Dubbo协议、HTTP协议及Hessian协议等。Dubbo协议是默认选择,采用NIO异步通讯,适用于高要求的内部服务通信。HTTP协议通用性强,利于跨语言调用;Hessian协议则在数据传输效率上有优势。选择合适协议需综合考虑性能需求、序列化方式、网络环境及安全性等因素。通过合理配置,可实现服务性能最优化及系统可靠性提升。
60 3
|
4月前
|
缓存 Dubbo Java
Dubbo服务消费者启动与订阅原理
该文章主要介绍了Dubbo服务消费者启动与订阅的原理,包括服务消费者的启动时机、启动过程以及订阅和感知最新提供者信息的方式。
Dubbo服务消费者启动与订阅原理
|
4月前
|
Dubbo 网络协议 Java
深入掌握Dubbo服务提供者发布与注册原理
该文章主要介绍了Dubbo服务提供者发布与注册的原理,包括服务发布的流程、多协议发布、构建Invoker、注册到注册中心等过程。
深入掌握Dubbo服务提供者发布与注册原理
|
4月前
|
C# 开发者 Windows
勇敢迈出第一步:手把手教你如何在WPF开源项目中贡献你的第一行代码,从选择项目到提交PR的全过程解析与实战技巧分享
【8月更文挑战第31天】本文指导您如何在Windows Presentation Foundation(WPF)相关的开源项目中贡献代码。无论您是初学者还是有经验的开发者,参与这类项目都能加深对WPF框架的理解并拓展职业履历。文章推荐了一些适合入门的项目如MvvmLight和MahApps.Metro,并详细介绍了从选择项目、设置开发环境到提交代码的全过程。通过具体示例,如添加按钮点击事件处理程序,帮助您迈出第一步。此外,还强调了提交Pull Request时保持专业沟通的重要性。参与开源不仅能提升技能,还能促进社区交流。
47 0
|
4月前
|
缓存 负载均衡 Dubbo
Dubbo服务集群容错原理(重要)
该文章主要介绍了Dubbo服务集群容错的原理,包括集群容错技术的概念、Dubbo中使用的集群容错技术种类及其原理。
|
7月前
|
Dubbo Java 应用服务中间件
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
|
2月前
|
Dubbo Java 应用服务中间件
Spring Cloud Dubbo:微服务通信的高效解决方案
【10月更文挑战第15天】随着信息技术的发展,微服务架构成为企业应用开发的主流。Spring Cloud Dubbo结合了Dubbo的高性能RPC和Spring Cloud的生态系统,提供高效、稳定的微服务通信解决方案。它支持多种通信协议,具备服务注册与发现、负载均衡及容错机制,简化了服务调用的复杂性,使开发者能更专注于业务逻辑的实现。
64 2
|
4月前
|
Dubbo Java 应用服务中间件
💥Spring Cloud Dubbo火爆来袭!微服务通信的终极利器,你知道它有多强大吗?🔥
【8月更文挑战第29天】随着信息技术的发展,微服务架构成为企业应用开发的主流模式,而高效的微服务通信至关重要。Spring Cloud Dubbo通过整合Dubbo与Spring Cloud的优势,提供高性能RPC通信及丰富的生态支持,包括服务注册与发现、负载均衡和容错机制等,简化了服务调用管理并支持多种通信协议,提升了系统的可伸缩性和稳定性,成为微服务通信领域的优选方案。开发者仅需关注业务逻辑,而无需过多关心底层通信细节,使得Spring Cloud Dubbo在未来微服务开发中将更加受到青睐。
87 0