这篇博文是我决心深度学习Dubbo框架时记录的笔记, 主题是Dubbo的拓展点, 下面的几个部分相对来说比较零散, 貌似是不和主题挂钩的 , 并且是一些很冷门的知识点 , 但是它们确实是深入学习Dubbo的前置知识

知识储备一: Dubbo的架构图

细化一下上图的各个组成部分:

  • 服务提供者
    • 提供服务接口的实现类
    • 注册服务 (远程注册, 本地注册)
    • 对外暴露服务
  • 注册中心
    • 保存 服务名称&服务地址 的映射关系
    • 当服务地址发生变动时, 主动通知消费者
  • 服务消费者
    • 启动时从注册中心拉取服务提供者的地址, 缓存在本地
    • 根据负载均衡策略选出一个服务进行远程调用 (Dubbo会将下面的信息封装成对象通过网络发送给服务提供者)
      • 参数1: 接口名
      • 参数2: 方法名
      • 参数3: 参数列表类型
      • 参数4: 参数值列表
  • 监控中心
    • 统计RPC过程的细节数据, 如: 服务调用次数, 调用时间

知识储备二: Dubbo中的核心概念

  • URL的作用

其实, Dubbo它作为一款RPC通信框架, 主体功能就是负责在服务集群中各个点之间进行数据的传递, 打个例子比如: 服务消费者调用服务的提供者,这个过程中的通信是Dubbo框架实现的, 通信的格式就好比自定义协议一样, Dubbo将服务提供者和服务消费者两种之间进行数据传递 需要的协议信息/ 端口号信息/ 请求那个接口 / 参数信息 / 账号 / 密码信息. 等一系列的信息进行封装,于是上图中的 URL 诞生了

  • 对URL的理解

对URL最直观的理解: URL是dobbo 对一系列数据的封装, 方便代码的编写, 参数的传递
很多人也将URL称为Dubbo的消息总线, 说URL贯穿于Dubbo的上下文, 我感觉到这个结论也许是这样得出的, 就是说 Dubbo作为一款RPC框架, 首要的任务就是 RPC 远程过程调用, 怎么样找到提供服务的机器呢? 无论是发起socket 还是借助Thrift或者Netty这种框架实现也罢, 前提是得知道提供服务的机器在哪里, 它的哪些接口对外暴露服务 , 没错! 这些信息都被Dubbo封装在了URL中

  • URL常见的组成
    • protobuf - 协议信息, 如 zk / Dubbo / http / Thrift
    • host/port - 目标主机端口信息
    • path - 接口的名称
    • parameters - 参数键值对信息
  • 典型的Dubbo URL格式
Copy
# 描述 Dubbo 协议的服务 Dubbo://192.168.1.6:20880/moe.cnkirito.sample.HelloService?timeout=3000 # 描述 zookeeper 注册中心 zookeeper://127.0.0.1:2181/org.apache.Dubbo.registry.RegistryService?application=demo-consumer&Dubbo=2.0.2&interface=org.apache.Dubbo.registry.RegistryService&pid=1214&qos.port=33333&timestamp=1545721981946 # 描述消费者 服务 consumer://30.5.120.217/org.apache.Dubbo.demo.DemoService?application=demo-consumer&category=consumers&check=false&Dubbo=2.0.2&interface=org.apache.Dubbo.demo.DemoService&methods=sayHello&pid=1209&qos.port=33333&side=consumer&timestamp=1545721827784 # for this case, url protocol = null, url host = 192.168.1.3, port = 20880, url path = null 192.168.1.3:20880 # for this case, url protocol = file, url host = null, url path = home/user1/router.js file:///home/user1/router.js?type=script ... 更多参照URL源码

Invoker#

invoker 直译调用者

  • 在服务提供方: invoker 对象被构造出来去调用提供服务的函数
  • 在服务的消费方: invoker用于调用 执行远程过程调用的类

Invocation#

指代程序中的调用对象, 包含了 接口名 / 方法名 / 参数类型列表 / 参数值列表 等

知识储备三: Java SPI (Service Provider Interface )#

怎么理解SPI机制呢?

如果说SPI是java提供的一种拓展机制, 其实是不明确的, 结合java本身的语言特性来说, SPI直观的看就是 基于接口的编程 + 策略模式 + 配置文件 组合实现的动态加载机制, 用大白话解释就是说, 一个框架的设计为了后期的拓展性, 肯定先会在顶层设计接口, 然后再为这些接口提供一些默认的实现类, 未了良好的拓展性, 如果想让, 如果想实现允许当前框架 识别 / 加载 / 使用 第三方提供的jar包时 , 就可以使用SPI实现接口的动态加载, 只要遵循SPI的规范, java就能将我们自己的类也加载进JVM供我们使用

说起来总归是模糊的, 看下面的小Demo自然就懂了

Copy
// 接口 public interface Person { String getName(); } // 实现类一: public class Student implements Person { @Override public String getName() { return "Student"; } } // 实现类二: public class Teacher implements