框架介绍

概述

Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。

Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

相关概念

dubbo运行架构如下图示

节点角色说明

调用关系说明

1、服务容器负责启动,加载,运行服务提供者。

2、服务提供者在启动时,向注册中心注册自己提供的服务。

3、服务消费者在启动时,向注册中心订阅自己所需的服务。

4、注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。

5、服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。

6、服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

关于dubbo 的特点分别有连通性、健壮性、伸缩性、以及向未来架构的升级性。特点的详细介绍也可以参考官方文档。

环境搭建

接下来逐步对dubbo各个模块的源码以及原理进行解析,目前dubbo框架已经交由Apache基金会进行孵化,被在github开源。

Dubbo 社区目前主力维护的有 2.6.x 和 2.7.x 两大版本,其中,

      · 2.6.x 主要以 bugfix 和少量 enhancements 为主,因此能完全保证稳定性

      · 2.7.x 作为社区的主要开发版本,得到持续更新并增加了大量新 feature 和优化,同时也带来了一些稳定性挑战

源码拉取

通过以下的这个命令签出最新的dubbo项目源码,并导入到IDEA中

git clone https://github.com/apache/dubbo.git dubbo

可以看到Dubbo被拆分成很多的Maven项目,在后续课程中会介绍左边每个模块的大致作用。

环境导入

在本次课程中,不仅讲解dubbo源码还会涉及到相关的基础知识,为了方便学员快速理解并掌握各个内容,已经准备好了相关工程,只需导入到IDEA中即可。对于工程中代码的具体作用,在后续课程会依次讲解

测试

(1) 安装zookeeper

(2) 修改官网案例,配置zookeeper地址

(3) 启动服务提供者,启动服务消费者

架构体系

源码结构

通过如下图形可以大致的了解到,dubbo源码各个模块的相关作用:

模块说明:

      · dubbo-common 公共逻辑模块:包括 Util 类和通用模型。

      · dubbo-remoting 远程通讯模块:相当于 Dubbo 协议的实现,如果 RPC 用 RMI协议则不需要使用此包。

      · dubbo-rpc 远程调用模块:抽象各种协议,以及动态代理,只包含一对一的调用,不关心集群的管理。

      · dubbo-cluster 集群模块:将多个服务提供方伪装为一个提供方,包括:负载均衡, 容错,路由等,集群的地址列表可以是静态配置的,也可以是由注册中心下发。

      · dubbo-registry 注册中心模块:基于注册中心下发地址的集群方式,以及对各种注册中心的抽象。

      · dubbo-monitor 监控模块:统计服务调用次数,调用时间的,调用链跟踪的服务。

      · dubbo-config 配置模块:是 Dubbo 对外的 API,用户通过 Config 使用Dubbo,隐藏 Dubbo 所有细节。

      · dubbo-container 容器模块:是一个 Standlone 的容器,以简单的 Main 加载 Spring 启动,因为服务通常不需要 Tomcat/JBoss 等 Web 容器的特性,没必要用 Web 容器去加载服务。

整体设计

图例说明:

      · 图中左边淡蓝背景的为服务消费方使用的接口,右边淡绿色背景的为服务提供方使用的接口,位于中轴线上的为双方都用到的接口。

      · 图中从下至上分为十层,各层均为单向依赖,右边的黑色箭头代表层之间的依赖关系,每一层都可以剥离上层被复用,其中,Service 和 Config 层为 API,其它各层均为 SPI。

      · 图中绿色小块的为扩展接口,蓝色小块为实现类,图中只显示用于关联各层的实现类。

      · 图中蓝色虚线为初始化过程,即启动时组装链,红色实线为方法调用过程,即运行时调时链,紫色三角箭头为继承,可以把子类看作父类的同一个节点,线上的文字为调用的方法。

各层说明

      · config 配置层:对外配置接口,以 ServiceConfigReferenceConfig 为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类

      · proxy 服务代理层:服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton, 以 ServiceProxy 为中心,扩展接口为 ProxyFactory

      · registry 注册中心层:封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为 RegistryFactoryRegistryRegistryService

      · cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 ClusterDirectoryRouterLoadBalance

      · monitor 监控层:RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为 MonitorFactoryMonitorMonitorService

      · protocol 远程调用层:封装 RPC 调用,以 InvocationResult 为中心,扩展接口为 ProtocolInvokerExporter

      · exchange 信息交换层:封装请求响应模式,同步转异步,以 RequestResponse 为中心,扩展接口为 ExchangerExchangeChannelExchangeClientExchangeServer

      · transport 网络传输层:抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 ChannelTransporterClientServerCodec

      · serialize 数据序列化层:可复用的一些工具,扩展接口为 SerializationObjectInputObjectOutputThreadPool

SPI机制

在 Dubbo 中,SPI 是一个非常重要的模块。基于 SPI,我们可以很容易的对 Dubbo 进行拓展。如果大家想要学习 Dubbo 的源码,SPI 机制务必弄懂。接下来,我们先来了解一下 Java SPI 与 Dubbo SPI 的用法,然后再来分析 Dubbo SPI 的源码。

SPI的概述

SPI的主要作用

SPI 全称为 Service Provider Interface,是一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能。

Java SPI 实际上是“基于接口的编程+策略模式+配置文件”组合实现的动态加载机制。

入门案例

首先,我们定义一个接口,名称为 Robot。

public interface Robot {void sayHello();
}

接下来定义两个实现类,分别为 OptimusPrime 和 Bumblebee。

public class OptimusPrime implements Robot {@Overridepublic void sayHello() {System.out.println("Hello, I am Optimus Prime.");}
}public class Bumblebee implements Robot {@Overridepublic void sayHello() {System.out.println("Hello, I am Bumblebee.");}
}

接下来 META-INF/services 文件夹下创建一个文件,名称为 Robot 的全限定名 com.itheima.java.spi.Robot。文件内容为实现类的全限定的类名,如下:

com.itheima.java.spi.impl.Bumblebee
com.itheima.java.spi.impl.OptimusPrime

做好所需的准备工作,接下来编写代码进行测试。

public class JavaSPITest {@Testpublic void sayHello() throws Exception {ServiceLoader serviceLoader = ServiceLoader.load(Robot.class);System.out.println("Java SPI");serviceLoader.forEach(Robot::sayHello);}
}

最后来看一下测试结果,如下:

从测试结果可以看出,我们的两个实现类被成功的加载,并输出了相应的内容。

总结

调用过程

      · 应用程序调用ServiceLoader.load方法,创建一个新的ServiceLoader,并实例化该类中的成员变量

      · 应用程序通过迭代器接口获取对象实例,ServiceLoader先判断成员变量providers对象中(LinkedHashMap<String,S>类型)是否有缓存实例对象,如果有缓存,直接返回。 如果没有缓存,执行类的装载

优点

使用 Java SPI 机制的优势是实现解耦,使得接口的定义与具体业务实现分离,而不是耦合在一起。应用进程可以根据实际业务情况启用或替换具体组件。

缺点

      · 不能按需加载。虽然 ServiceLoader 做了延迟载入,但是基本只能通过遍历全部获取,也就是接口的实现类得全部载入并实例化一遍。如果你并不想用某些实现类,或者某些类实例化很耗时,它也被载入并实例化了,这就造成了浪费。

      · 获取某个实现类的方式不够灵活,只能通过 Iterator 形式获取,不能根据某个参数来获取对应的实现类。

      · 多个并发多线程使用 ServiceLoader 类的实例是不安全的。

      · 加载不到实现类时抛出并不是真正原因的异常,错误很难定位。

Dubbo中的SPI

概述

Dubbo 并未使用 Java SPI,而是重新实现了一套功能更强的 SPI 机制。Dubbo SPI 的相关逻辑被封装在了 ExtensionLoader 类中,通过 ExtensionLoader,我们可以加载指定的实现类。

入门案例

与 Java SPI 实现类配置不同,Dubbo SPI 是通过键值对的方式进行配置,这样我们可以按需加载指定的实现类。下面来演示 Dubbo SPI 的用法:

Dubbo SPI 所需的配置文件需放置在 META-INF/dubbo 路径下,与 Java SPI 实现类配置不同,Dubbo SPI 是通过键值对的方式进行配置,配置内容如下。

optimusPrime = org.apache.spi.OptimusPrime
bumblebee = org.apache.spi.Bumblebee

在使用Dubbo SPI 时,需要在接口上标注 @SPI 注解。

@SPI
public interface Robot {void sayHello();
}

通过 ExtensionLoader,我们可以加载指定的实现类,下面来演示 Dubbo SPI :

public class DubboSPITest {@Testpublic void sayHello() throws Exception {ExtensionLoader extensionLoader = ExtensionLoader.getExtensionLoader(Robot.class);Robot optimusPrime = extensionLoader.getExtension("optimusPrime");optimusPrime.sayHello();Robot bumblebee = extensionLoader.getExtension("bumblebee");bumblebee.sayHello();}
}

测试结果如下:

Dubbo SPI 除了支持按需加载接口实现类,还增加了 IOC 和 AOP 等特性,这些特性将会在接下来的源码分析章节中一一进行介绍。

源码分析

上一章简单演示了 Dubbo SPI 的使用方法,首先通过 ExtensionLoader 的 getExtensionLoader 方法获取一个 ExtensionLoader 实例,然后再通过 ExtensionLoader 的 getExtension 方法获取拓展类对象。下面我们从 ExtensionLoader 的 getExtension 方法作为入口,对拓展类对象的获取过程进行详细的分析。

    public T getExtension(String name) {if (StringUtils.isEmpty(name)) {throw new IllegalArgumentException("Extension name == null");}if ("true".equals(name)) {// 获取默认的拓展实现类return getDefaultExtension();}// Holder,顾名思义,用于持有目标对象Holder

【Java教程】dubbo源码解析-SPI机制相关推荐

  1. Dubbo源码解析-——SPI机制

    文章目录 一.什么是SPI机制 二.Java原生的SPI机制 2.1.javaSPI示例 2.1.1.编写接口和实现类 2.1.2.编写配置文件 2.1.3.通过SPI机制加载实现类 2.1.4.JA ...

  2. dubbo源码解析-SPI机制

    SPI,Service Provider Interface,服务提供者接口,是一种服务发现机制. JDK 的 SPI 规范 JDK 的 SPI 规范规定:  接口名:可随意定义  实现类名:可随 ...

  3. Dubbo 源码分析 - SPI 机制

    1.简介 SPI 全称为 Service Provider Interface,是一种服务发现机制.SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类.这样可以 ...

  4. dubbo源码解析-spi(二)

    前言 上一篇简单的介绍了spi的基本一些概念,在末尾也提到了,dubbo对jdk的spi进行了一些改进,具体改进了什么,来看看文档的描述 JDK 标准的 SPI 会一次性实例化扩展点所有实现,如果有扩 ...

  5. 【dubbo源码解析】 --- dubbo spi 机制(@SPI、@Adaptive)详解

    本文对应源码地址:https://github.com/nieandsun/dubbo-study 注意:dubbo 要求SPI扩展点的实现类必须要有一个无参构造,除了Wrapper实现类之外 文章目 ...

  6. dubbo源码解析(十)远程通信——Exchange层

    远程通讯--Exchange层 目标:介绍Exchange层的相关设计和逻辑.介绍dubbo-remoting-api中的exchange包内的源码解析. 前言 上一篇文章我讲的是dubbo框架设计中 ...

  7. Dubbo源码解析 - 远程暴露

    作者:肥朝 原文地址:http://www.jianshu.com/p/893f7e6e0c58 友情提示:欢迎关注公众号[芋道源码].????关注后,拉你进[源码圈]微信群和[肥朝]搞基嗨皮. 友情 ...

  8. dubbo源码解析(九)远程通信——Transport层

    远程通讯--Transport层 目标:介绍Transport层的相关设计和逻辑.介绍dubbo-remoting-api中的transport包内的源码解析. 前言 先预警一下,该文篇幅会很长,做好 ...

  9. dubbo(5) Dubbo源码解析之服务调用过程

    来源:https://juejin.im/post/5ca4a1286fb9a05e731fc042 Dubbo源码解析之服务调用过程 简介 在前面的文章中,我们分析了 Dubbo SPI.服务导出与 ...

  10. dubbo源码解析之框架粗谈

    dubbo框架设计 一.dubbo框架整体设计 二.各层说明 三.dubbo工程模块分包 四.依赖关系 五.调用链 文章系列 [一.dubbo源码解析之框架粗谈] [二.dubbo源码解析之dubbo ...

最新文章

  1. 一文读懂机器学习、数据科学、人工智能、深度学习和统计学之间的区别!
  2. 使用动态代理,提高工作效率
  3. 解决“element表单验证输入的数字检测出来是string”的问题
  4. 【转】【WPF】WPF样式(Style)—触发器
  5. Android Studio引入.so文件的正确姿势 以及调用.so 文件时报错has text relocations 解决
  6. python mro c3_python的MRO和C3算法
  7. spring 框架(一)
  8. SuperSocket框架命令不被识别的一种原因
  9. 算法学习(四)冒泡排序
  10. liunx 加入域控_[整理篇]linux加入windows域之完美方案
  11. 游戏服务器的架构设计(一点参考,实际价值似乎不大……)
  12. 生成交叉表的SQL基本语句
  13. caffe face 实现人脸相似度识别 c++版本
  14. 智能汽车路径规划学习-Dijkstra、蚁群算法
  15. 25.HTTP协议和WEB服务器APACHE
  16. 修改输入框placeholder文字样式(颜色、字号等)
  17. Android Studio kotlin代码莫名出现“lazy”,“arrayListOf”,“let”等关键字变红的问题
  18. 大学物理实验长度的测量实验报告_长度测量实验报告.doc
  19. 计算机初中几年级考,2021年小升初考试时间(2021小升初考试是几月几号 )
  20. 鸿蒙系统源代码解析,鸿蒙内核源码分析(系统调用篇) | 图解系统调用全貌

热门文章

  1. qpsk 16qam matlab,谁能提供16qam和qpsk调制解调的ofdm程序
  2. wx僵尸粉检测,真实好友1.0(无障碍检测好友状态)
  3. 前端开发之谷歌实用插件fehelper JSON助手
  4. 基于asp.net大学生助学贷款管理系统#毕业设计
  5. linux软连接j,Linux(ubuntu)安装JLink 驱动
  6. 华为复制加密门禁卡_小米手机的NFC可以随便复制其它小区用的门禁卡吗?
  7. 2015-2022年历年真题考研数学二难度概述
  8. 大数据分析-实验八 鸢尾花数据集分类
  9. vivox50支持鸿蒙,vivo X50系列极致轻薄的机身下,还有哪些功能和亮点?
  10. linux下安装inode客户端