阅读Dubbo源码无从下手?
Apache Dubbo作为一款高性能、轻量级的开源 Java RPC 框架,已经广泛的运用在生产中。并且在我们升职加薪的路上,阅读Dubbo源码、理解Dubbo的设计思想以及可以举一反三应用于实践的能力,可以极大的提高面试时的议价筹码。
今天起,我们将展开一个新的系列——Dubbo源码阅读,一起开启对Dubbo这个优秀RPC框架的学习之路。本篇将介绍Dubbo的架构和角色、源码环境的搭建、项目结构解读和运行官方Demo。
官网:http://dubbo.apache.org/
架构和角色
Dubbo有三大核心能力:提供了面向接口的远程方法调用;可靠、智能的容错和负载均衡;服务自动注册和发现能力。简单地说, Dubbo 是一个分布式服务框架,致力于提供高性能、透明化的 RPC 远程服务调用方案以及服务治理方案,以帮助我们解决微服务架构落地时的问题。
如上图所示,Dubbo的角色主要分为四种:
Consumer:服务消费者。在它启动的时候,会向 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:监控中心。非必须角色, 宕机不会影响 其他角色功能,用于统计服务的调用次数和调用时间。Provider 和 Consumer 在运行过程中,会在内存中统计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
源码环境搭建
1.Fork源码到自己的GitHub仓库。
2.下载项目到本地:
git clone git@github.com:xxxxxxxx/dubbo.git
3.Check Out分支
git checkout -b dubbo-2.7.x dubbo-2.7.x
4.使用mvn编译项目
mvn clean install -Dmaven.test.skip=true
如果编译成功,可以看到如下效果:
Zookeeper注册中心搭建
除了源码编译,dubbo 启动还需要依赖注册中心,这里我们使用 zookeeper。
1.首先下载源码。https://archive.apache.org/dist/zookeeper/zookeeper-3.4.14/
2.解压缩源码包并且进入源码目录
tar -zxf zookeeper-3.4.14.tar.gz
cd zookeeper-3.4.14
3.复制配置文件
cd conf
cp zoo_sample.cfg zoo.cfg
4.启动项目
./bin/zkServer.sh start
项目结构
使用Idea打开项目之后,可以看到Dubbo的项目结构如下:
dubbo-rpc 模块:Dubbo 中对远程调用协议进行抽象的模块,其中抽象了各种协议,依赖于 dubbo-remoting 模块的远程调用功能。dubbo-rpc 模块的实现中只包含一对一的调用,不关心集群的相关内容。
dubbo 的很多模块层级结构相似,为一个抽象的 api 模块和其他实现 api 模块的子模块。
以 dubbo-rpc 为例,dubbo-rpc-api 子模块是核心抽象,其他子模块是针对具体协议的实现,例如,dubbo-rpc-dubbo 子模块是对 Dubbo 协议的实现,依赖了 dubbo-remoting-netty4 等 dubbo-remoting 子模块。
dubbo-cluster 模块:负责管理 dubbo 集群的模块,提供了负载均衡、容错、路由等一系列集群相关的功能,最终的目的是将多个 Provider 伪装为一个 Provider,这样 Consumer 就可以像调用一个 Provider 那样调用 Provider 集群了。
dubbo-configcenter 模块:Dubbo 的动态配置模块,主要负责外部化配置以及服务治理规则的存储与通知,提供了多个子模块用来接入多种开源的服务发现组件。
dubbo-common 模块:Dubbo 的一个公共模块,其中有很多工具类以及公共逻辑,比如 Dubbo 的 SPI 实现、时间轮实现、动态编译器等。
dubbo-remoting 模块:Dubbo 的远程通信模块,其中的子模块依赖各种开源组件实现远程通信。有如下主要实现,例如,dubbo-remoting-netty4 子模块依赖 Netty 4 实现远程通信,dubbo-remoting-zookeeper 通过 Apache Curator 实现与 ZooKeeper 集群的交互。
dubbo-registry 模块:Dubbo 中负责与多种开源注册中心进行交互的模块,提供注册中心的能力。其中,dubbo-registry-zookeeper 子模块是 Dubbo 接入 ZooKeeper 注册中心的具体实现。
dubbo-monitor 模块:Dubbo 的监控模块,主要用于统计服务调用次数、调用时间以及实现调用链跟踪的服务。
dubbo-config 模块:Dubbo 对外暴露的配置都是由该模块进行解析的,用户无需了解细节,只需按照配置规则进行配置。dubbo-config-api 子模块负责处理 API 方式使用时的相关配置,dubbo-config-spring 子模块负责处理与 Spring 集成使用时的相关配置方式。
dubbo-metadata 模块:Dubbo 的元数据模块。dubbo-metadata 模块的实现套路也是有一个 api 子模块进行抽象,然后其他子模块进行具体实现。
官方Demo
Dubbo 为我们提供了三种非常基础的示例程序,在 dubbo-demo 模块下。
这四个子模块分别为 demo-api(demo 的api抽象)、demo-api(使用 api 配置)、demo-xml(xml 方式配置)、demo-annotation(注解配置)。
1、dubbo-demo-interface
这里定义的 demo 所需要使用的业务接口 DemoService。
public interface DemoService {
String sayHello(String name); // 同步调用
default CompletableFuture<String> sayHelloAsync(String name) {
return CompletableFuture.completedFuture(sayHello(name));
}//异步
}
因为远程调用都需要有 provider 和 counsumer 两个角色,一个用来提供服务,一个用来调用服务,两者对业务接口一个是实现,一个是示例化调用。这里的三个子模块具体实现都是基于这样对逻辑。
2、dubbo-demo-annotation
因为三个子模块实现大同小异,这里我们以注解配置方式为例。
因为三个子模块实现大同小异,这里我们只以注解配置方式为例。
dubbo.registry.address=zookeeper://localhost:2181
registryConfig.setAddress("zookeeper://localhost:2181");
然后分别启动 provider 和 consumer。consumer 成功输出结果。
原理:
先看 provider 的实现
public class Application {
public static void main(String[] args) throws Exception {
// 使用AnnotationConfigApplicationContext初始化Spring容器,
// 从ProviderConfiguration这个类的注解上拿相关配置信息
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(
ProviderConfiguration.class);
context.start();
System.in.read();
}
// 配置类
//@EnableDubbo注解指定包下的Bean都会被扫描,并做Dubbo服务暴露出去
"org.apache.dubbo.demo.provider") (scanBasePackages =
// PropertySource注解指定了其他配置信息
"classpath:/spring/dubbo-provider.properties") (
static class ProviderConfiguration {
public RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("zookeeper://127.0.0.1:2181");
return registryConfig;
}
}
}
DemoServiceImpl 实现了 DemoService 接口,在 org.apache.dubbo.demo.provider 目录下被扫描到从而暴露成 Dubbo 服务。
在看consumer模块,Application 通过 AnnotationConfigApplicationContext 初始化 Spring 容器,会扫描指定目录下 DemoServiceComponent 这个 Bean,然后通过 @Reference 注解注入 Dubbo 服务相关的 Bean
"demoServiceComponent") (
public class DemoServiceComponent implements DemoService {
// 注入Dubbo服务
private DemoService demoService;
public String sayHello(String name) {
return demoService.sayHello(name);
}
}
希望上述内容可以帮助到你。下一篇将讲解 JDK SPI 和 Dubbo SPI。