反正我收藏了!Apache Dubbo介绍以及扩展机制SPI

Apache Dubbo 介绍首先我们先问一句 , Apahce Dubbo 是什么?这个问题恐怕我不会给太多答案给你 , 因为 Dubbo 的官网其实描述非常清楚明了 , 而且具备了非常全面的架构解析以及源码解析 。 所以 , 学习 Dubbo 非常有必要去 官网传送门 。
对于 Dubbo 我觉得从官网来的一句简介非常贴切:
Apache Dubbo? 是一款微服务框架(Microservices Framework) , 它提供高性能 RPC 通信、服务发现、流量管理等服务治理能力 , 为你提供构建大规模微服务集群所需的全套解决方案 。
从简介我们大致上可以了解 , Dubbo 就是一个微服务框架 。 它提供了挺多的微服务相关的功能 , 例如:

  1. Transparent interface based RPC 基于接口的 RPC
  2. Intelligent load balancing 智能负载均衡
  3. Automatic service registration and discovery 服务发现与服务注册
  4. High extensibility 高性能扩展
  5. Runtime traffic routing 实时流量路由
  6. Visualized service governance 可视化服务治理
同样 , 其实如果你们平时使用 Spring Cloud 进行开发的话 , 我们也可以同样感受到非常多这种微服务的特性 , 例如 Spring Cloud Netflix 提供的服务注册/发现 , 负载均衡 , 服务调用 , 可视化治理等等 。
Dubbo SPI首先学习 Java 的同学都知道 Java 原生提供了一种基于接口的服务发现机制 , 它的名字就是 SPI (Service Provider Interface) 。 就是通过接口我们可以定义多个不同业务逻辑的实现类 , 并配置在制定文件中;而 Java 会通过读取文件 , 读取到你所指定的实现类并进行实例化/调用等操作从而实现以非侵入方式进行逻辑替换 。 典型的例子就是 JDBC 中的 DriverManager 通过 SPI 可以管理和注册不同数据库的 Driver , 相信你们也可以感受到一个 DriverManager 可以接入不同数据库厂商的驱动 。
那么 SPI 跟 Dubbo 有什么关系呢?其实我们先来看一张 Dubbo 的架构图 。
反正我收藏了!Apache Dubbo介绍以及扩展机制SPI文章插图
从架构图上来说 , Dubbo 采用了分层的项目结构以及插件化的形式实现的 。 除了 Service 和 Config , 实际上其他层面都是使用了 SPI , 也就是 Dubbo 通过 SPI 这种机制来实现框架最大限度的灵活性 , 就好像 Spring 在框架外或者框架内都提供了非常多的扩展机制 , 可以说这是框架的必备技能 。 以下我举几个例子说明一下 。 例如 Proxy 是服务代理层 , 在这一层我们通过 SPI 可以自定义服务注册中心;Cluster 是属于路由层 , 在这层主要处理的多个服务提供者的路由规则/负载均衡/集群容错的实现 。 那么 Dubbo 也可以通过 SPI 来进行一个规则或均衡策略的选择实现逻辑处理替换;甚至在 Monitor 监控层 , 我们也可以进行自定义的实现等等 。
现在你可以发现了吧 , 实际上 Dubbo 的分层架构使得 Dubbo 的每层都是可以替换 , 这个已经说明了 Dubbo 的扩展性是极强的 。
但是 Java SPI 和 Dubbo SPI 是同一个东西吗?原理层面来说 , 他两是一样的;实现上来说 , Dubbo SPI 是 Java SPI 的增强版 。 它主要从几方面增强:
  1. 按需加载 , 非原生的一次性加载
  2. 对 SPI 加载有着更好的故障追溯
  3. 更多的扩展点 , 例如 IOC 以及 AOP 的支持
这些东西都是非常优秀的一些设计理念 , 也是我们在源码解析的时候可以着重学习的地方!
Let’s Go!
Dubbo SPI 的例子为了在源码解析的时候有更直观的感受 , 我们直接敲一个例子吧 。
导入依赖
com.alibabadubbo2.7.5创建 SPI 所需的一个接口
package com.dubbo.demo;public interface UserService { public void findById(int id);}【反正我收藏了!Apache Dubbo介绍以及扩展机制SPI】虚拟两个不同的业务场景 , 我们写两个 UserService 的实现类 UserServiceImpl1.java 和 UserServiceImpl2.java 。
package com.dubbo.demo.impl;public class UserServiceImpl1{ public void findById(int id) {System.out.println("UserServiceImpl1 find User " + id);}}UserServiceImpl2.java
package com.dubbo.demo.impl;public class UserServiceImpl2{ public void findById(int id) {System.out.println("UserServiceImpl2 find User " + id);}}然后我们在 resource 创建一个名为 services 文件夹 , 然后创建一个名字为接口全限定名配置的文件 com.dubbo.demo.UserService 。 在文件中键入内容:
userServiceImpl1=com.dubbo.demo.impl.UserServiceImpl1然后最后我们测试类 SPIDemo.java
public class SPIDemo { public static void main(String[] args) {ExtensionLoader