Dubbo源码解读与实战:(一)源码环境搭建

Myth丶恋晨 2022-11-29 03:16 442阅读 0赞

前言

搭建环境之前,先看官网介绍,大致了解Dubbo的架构思想,这个可以帮助你后面更好的了解Dubbo的基本功能以及核心角色

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NocmVrMTE_size_16_color_FFFFFF_t_70

Registry:注册中心

  1. 负责服务地址的注册与查找,服务ProviderConsumer只在启动时与注册中心交互。注册中心通过长连接感知Provider的存在,当Provider出现宕机时,注册中心会立即推送通知给Consumer

Provider:服务提供者

  1. 在他启动的时候,会向Registry发送注册信息,会将自己服务的IP地址和相关配置信息封装成URL添加在zookeeper

Consumer:服务消费着

  1. 在他启动的时候,会向 Registry 进行订阅操作。订阅操作会从 ZooKeeper 中获取 Provider 注册的 URL,并在 ZooKeeper 中添加相应的监听器。获取到 Provider URL 之后,Consumer 会根据负载均衡算法从多个 Provider 中选择一个 Provider 并与其建立连接,最后发起对 Provider RPC 调用。 如果 Provider URL 发生变更,Consumer 将会通过之前订阅过程中在注册中心添加的监听器,获取到最新的 Provider URL 信息,进行相应的调整,比如断开与宕机 Provider 的连接,并与新的 Provider 建立连接。Consumer Provider 建立的是长连接,且 Consumer 会缓存 Provider 信息,所以一旦连接建立,即使注册中心宕机,也不会影响已运行的 Provider Consumer

Monitor:监控中心

  1. 用于统计服务的调用次数和调用时间。Provider Consumer 在运行过程中,会在内存中统计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。监控中心在上面的架构图中并不是必要角色,监控中心宕机不会影响 ProviderConsumer 以及 Registry 的功能,只会丢失监控数据而已。

搭建源码环境

Dobbo源码已经开源,地址 https://github.com/apache/dubbo

我们可以将源码fork到自己仓库,再下载到本地,dobbo是通过maven编译打包的,成功之后如下图:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NocmVrMTE_size_16_color_FFFFFF_t_70 1

下面简单介绍一下dubbo的核心模块:这个源码主要是在dubbo2.7x版本,请切换到此版本。

dubbo-common 模块:

  1. Dubbo的公共模块,主要是一些工具类和一些公共逻辑,例如后面紧接着要介绍的 Dubbo SPI 实现、时间轮实现、动态编译器等。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NocmVrMTE_size_16_color_FFFFFF_t_70 2

dubbo-remoting 模块:

Dubbo 的远程通信模块,其中的子模块依赖各种开源组件实现远程通信。在 dubbo-remoting-api 子模块中定义该模块的抽象概念,在其他子模块中依赖其他开源组件进行实现,例如,dubbo-remoting-netty4 子模块依赖 Netty 4 实现远程通信,dubbo-remoting-zookeeper 通过 Apache Curator 实现与 ZooKeeper 集群的交互。

20200819114652740.png

dubbo-rpc 模块:

Dubbo 中对远程调用协议进行抽象的模块,其中抽象了各种协议,依赖于 dubbo-remoting 模块的远程调用功能。dubbo-rpc-api 子模块是核心抽象,其他子模块是针对具体协议的实现,例如,dubbo-rpc-dubbo 子模块是对 Dubbo 协议的实现,依赖了 dubbo-remoting-netty4 等 dubbo-remoting 子模块。 dubbo-rpc 模块的实现中只包含一对一的调用,不关心集群的相关内容。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NocmVrMTE_size_16_color_FFFFFF_t_70 3

dubbo-cluster 模块:

Dubbo 中负责管理集群的模块,提供了负载均衡、容错、路由等一系列集群相关的功能,最终的目的是将多个 Provider 伪装为一个 Provider,这样 Consumer 就可以像调用一个 Provider 那样调用 Provider 集群了。

dubbo-registry 模块:

Dubbo 中负责与多种开源注册中心进行交互的模块,提供注册中心的能力。其中, dubbo-registry-api 子模块是顶层抽象,其他子模块是针对具体开源注册中心组件的具体实现,例如,dubbo-registry-zookeeper 子模块是 Dubbo 接入 ZooKeeper 的具体实现。

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3NocmVrMTE_size_16_color_FFFFFF_t_70 4

dubbo-monitor 模块:

Dubbo 的监控模块,主要用于统计服务调用次数、调用时间以及实现调用链跟踪的服务。

dubbo-config 模块:

Dubbo 对外暴露的配置都是由该模块进行解析的。例如,dubbo-config-api 子模块负责处理 API 方式使用时的相关配置,dubbo-config-spring 子模块负责处理与 Spring 集成使用时的相关配置方式。有了 dubbo-config 模块,用户只需要了解 Dubbo 配置的规则即可,无须了解 Dubbo 内部的细节。

20200819115828481.png

dubbo-metadata 模块:

Dubbo 的元数据模块(后续会详细介绍元数据的内容)。dubbo-metadata 模块的实现套路也是有一个 api 子模块进行抽象,然后其他子模块进行具体实现。

dubbo-configcenter 模块:

Dubbo 的动态配置模块,主要负责外部化配置以及服务治理规则的存储与通知,提供了多个子模块用来接入多种开源的服务发现组件。

20200819134544106.png

Dubbo 源码中的 Demo 示例

dubbo-demo-interface:

  1. 在使用 Dubbo 之前,你还需要一个业务接口,这个业务接口可以认为是 Dubbo Provider Dubbo Consumer 的公约,反映出很多信息:这个接口模块就是定义接口模块。生成和消费服务都要依赖这个模块。

dubbo-demo-api:

  1. 不能依赖于 Spring 框架,只能使用 API 来构建 Dubbo Provider Consumer,比较典型的一种场景就是在写 SDK 的时候。
  2. 下面是dubbo-demo-api-provider 模块,main入口方向。
  3. private static void startWithBootstrap() {
  4. // 创建一个ServiceConfig的实例,泛型参数是业务接口实现类,
  5. // 即DemoServiceImpl
  6. ServiceConfig<DemoServiceImpl> service = new ServiceConfig<>();
  7. // 指定业务接口
  8. service.setInterface(DemoService.class);
  9. // 指定业务接口的实现,由该对象来处理Consumer的请求
  10. service.setRef(new DemoServiceImpl());
  11. // 获取DubboBootstrap实例,这是个单例的对象
  12. DubboBootstrap bootstrap = DubboBootstrap.getInstance();
  13. //生成一个 ApplicationConfig 的实例、指定ZK地址以及ServiceConfig实例
  14. bootstrap.application(new ApplicationConfig("dubbo-demo-api-provider"))
  15. .registry(new RegistryConfig("zookeeper://127.0.0.1:2181"))
  16. .service(service)
  17. .start()
  18. .await();
  19. }
  20. 这里,同样会有一个 DemoServiceImpl 实现了 DemoService 接口,并且在 org.apache.dubbo.demo.provider 目录下,能被扫描到,暴露成 Dubbo 服务。
  21. 在看看dobbo-demo-api-comsummer模块,main入口方法怎么去通过注册中心获取生产者信息再去调用
  22. private static void runWithBootstrap() {
  23. // 创建ReferenceConfig,其中指定了引用的接口DemoService
  24. ReferenceConfig<DemoService> reference = new ReferenceConfig<>();
  25. reference.setInterface(DemoService.class);
  26. reference.setGeneric("true");
  27. // 创建DubboBootstrap,指定ApplicationConfig以及RegistryConfig
  28. DubboBootstrap bootstrap = DubboBootstrap.getInstance();
  29. bootstrap.application(new ApplicationConfig("dubbo-demo-api-consumer"))
  30. .registry(new RegistryConfig("zookeeper://127.0.0.1:2181"))
  31. .reference(reference)
  32. .start();
  33. // 获取DemoService实例并调用其方法
  34. DemoService demoService = ReferenceConfigCache.getCache().get(reference);
  35. String message = demoService.sayHello("dubbo man");
  36. System.out.println(message);
  37. // generic invoke
  38. GenericService genericService = (GenericService) demoService;
  39. Object genericInvokeResult = genericService.$invoke("sayHello", new String[] { String.class.getName() },
  40. new Object[] { "dubbo generic invoke" });
  41. System.out.println(genericInvokeResult);
  42. }

dubbo-demo-xml:

  1. 消费服务的resource/spring/dubbo-consumer.xml 配置文件中,会指定注册中心地址(就是前面 ZooKeeper 的地址),这样 Dubbo 才能从 ZooKeeper 中拉取到 Provider 暴露的服务列表信息
  2. <beans>
  3. <dubbo:application name="demo-consumer"/>
  4. <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
  5. <dubbo:reference id="demoService" check="false" interface="org.apache.dubbo.demo.DemoService"/>
  6. </beans>
  7. 在生成服务的resource/spring/dubbo-provider.xml配置文件,配置了相关信息。
  8. <?xml version="1.0" encoding="UTF-8"?>
  9. <dubbo:application metadata-type="remote" name="demo-provider"/>
  10. <dubbo:metadata-report address="zookeeper://127.0.0.1:2181"/>
  11. <dubbo:registry address="zookeeper://127.0.0.1:2181"/>
  12. <dubbo:protocol name="dubbo"/>
  13. <bean id="demoService" class="org.apache.dubbo.demo.provider.DemoServiceImpl"/>
  14. <dubbo:service interface="org.apache.dubbo.demo.DemoService" ref="demoService"/>
  15. </beans>

dubbo-demo-annotation:

  1. 注解模块就是把xml的转换成注解。大致和xml差不多。
  2. public class Application {
  3. public static void main(String[] args) throws Exception {
  4. // 使用AnnotationConfigApplicationContext初始化Spring容器,
  5. // 从ProviderConfiguration这个类的注解上拿相关配置信息
  6. AnnotationConfigApplicationContext context =
  7. new AnnotationConfigApplicationContext(
  8. ProviderConfiguration.class);
  9. context.start();
  10. System.in.read();
  11. }
  12. @Configuration // 配置类
  13. // @EnableDubbo注解指定包下的Bean都会被扫描,并做Dubbo服务暴露出去
  14. @EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider")
  15. // @PropertySource注解指定了其他配置信息
  16. @PropertySource("classpath:/spring/dubbo-provider.properties")
  17. static class ProviderConfiguration {
  18. @Bean
  19. public RegistryConfig registryConfig() {
  20. RegistryConfig registryConfig = new RegistryConfig();
  21. registryConfig.setAddress("zookeeper://127.0.0.1:2181");
  22. return registryConfig;
  23. }
  24. }
  25. }
  26. 这里,同样会有一个 DemoServiceImpl 实现了 DemoService 接口,并且在 org.apache.dubbo.demo.provider 目录下,能被扫描到,暴露成 Dubbo 服务。
  27. 接着再来看 dubbo-demo-annotation-consumer 模块,其中 Application 中也是通过 AnnotationConfigApplicationContext 初始化 Spring 容器,也会扫描指定目录下的 Bean,会扫到 DemoServiceComponent 这个 Bean,其中就通过 @Reference 注解注入 Dubbo 服务相关的 Bean
  28. @Component("demoServiceComponent")
  29. public class DemoServiceComponent implements DemoService {
  30. @Reference // 注入Dubbo服务
  31. private DemoService demoService;
  32. @Override
  33. public String sayHello(String name) {
  34. return demoService.sayHello(name);
  35. }
  36. // 其他方法
  37. }

下一节:Dubbo源码解读与实战:(二)Dubbo 的配置总线:抓住 URL,就理解了半个 Dubbo

发表评论

表情:
评论列表 (有 0 条评论,442人围观)

还没有评论,来说两句吧...

相关阅读

    相关 dubbo环境

    dubbo由于很多jar包无法下载到而在导入后存在大量错误。这里记录一下解决方案。         1、通过maven安装alibaba open parent。地址http