首页 > 其他分享 >理解 Apache ShardingSphere 的 SPI,以及为何它比 Dubbo 更简单

理解 Apache ShardingSphere 的 SPI,以及为何它比 Dubbo 更简单

时间:2024-01-04 23:33:10浏览次数:26  
标签:Dubbo Java ShardingSphere SPI return final

为什么学习 ShardingSphere 的 SPI?

你可能已经熟悉 Java 和 Dubbo 的 SPI(Service Provider Interface)机制,所以你可能会想:“为什么要学习 ShardingSphere 的 SPI 机制呢?”原因非常简单:

  1. ShardingSphere 的源代码更简单、更容易适应。
  2. ShardingSphere 的 SPI 机制执行非常顺畅,日常操作所需的代码较少。与 Dubbo 的 SPI 机制以及与 IoC 相关的其他功能不同,ShardingSphere 的 SPI 只保留了基本结构,使用起来轻松自如。

理解 ShardingSphere 的 SPI

我们还必须提到 Java SPI 机制存在一些缺陷:

  1. 具有多个并发线程的 ServiceLoader 类实例不安全。
  2. 每次获取元素时,需要迭代所有元素,不能按需加载。
  3. 当实现类加载失败时,会提示异常而不指示真正的原因,使错误难以定位。
  4. 获取实现类的方式不够灵活。只能通过 Iterator 形式获取,而不能根据一个参数获取相应的实现类。

在此背景下,让我们看看 ShardingSphere 如何通过简单的方式解决这些问题。

加载 SPI 类

Dubbo 是其自己 SPI 的直接重写,包括 SPI 文件名和文件配置方式,与 JDK 形成鲜明对比。让我们简要比较一下这两者的使用:

Java SPI

将接口实现类添加到 META-INF/services 文件夹下:

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

Dubbo SPI

将接口的实现类添加到 META-INF/services 文件夹下,并通过 keyvalue 配置,如下例所示:

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

现在我们可以看到,Dubbo 的 Java SPI 与 JDK SPI 完全不同。

ShardingSphere 如何简单地扩展 JDK SPI?

与 Dubbo 的实现理念不同,ShardingSphere 通过较少的代码扩展了 JDK SPI。

  1. 配置与 Java SPI 完全相同。以 DialectTableMetaDataLoader 接口实现类为例:
DialectTableMetaDataLoader.class
public interface DialectTableMetaDataLoader extends StatelessTypedSPI {
    Map<String, TableMetaData> load(DataSource dataSource, Collection<String> tables) throws SQLException;
}

public interface TypedSPI {
    String getType();
    default Collection<String> getTypeAliases() {
        return Collections.emptyList();
    }
}

StatelessTypedSPI 接口从 TypedSPI 继承,多个接口用于满足单一接口责任的原则。TypedSPIMap 的关键,子类需要指定自己的 SPI。

在这里,您无需关心 DialectTableMetaDataLoader 接口定义了哪些方法,只需关注子类如何通过 SPI 加载即可。如果是 Java SPI,要加载子类,只需在 META-INF/services 中定义它的全类名。

理解 Apache ShardingSphere 的 SPI,以及为何它比 Dubbo 更简单_加载

正如您所看到的,与本机 Java SPI 配置完全相同。那么它的缺点呢?

使用工厂方法模式

对于每个需要通过 SPI 扩展和创建的接口,通常都有一个类似的 xxDataLoaderFactory 用于创建和获取指定的 SPI 扩展类。

DialectTableMetaDataLoaderFactory
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class DialectTableMetaDataLoaderFactory {
    public static Optional<DialectTableMetaDataLoader> newInstance(final DatabaseType databaseType) {
        return TypedSPILoader.findService(DialectTableMetaDataLoader.class, databaseType.getName());
    }
}

在这里,使用了静态代码块,所有的 DialectTableMetaDataLoader 实现类都是在类加载过程中通过 ShardingSphereServiceLoader.register 注册的。通过使用 TypedSPILoader.findService,我们可以获取到我们指定的 spi 扩展类。

TypedSPILoader.findService(final Class<T> spiClass, final String type)

因此,我们只需关注 TypedSPILoader.findService 方法。

TypedSPILoader

TypedSPILoader 中的 findService 方法本质上是调用了 ShardingSphereServiceLoadergetSingletonServiceInstancesmethod

public static <T extends StatelessTypedSPI> Optional<T> findService(final Class<T> spiClass, final String type) {
    for (T each : ShardingSphereServiceLoader.getSingletonServiceInstances(spiClass)) {
        if (matchesType(type, each)) {
            return Optional.of(each);
        }
    }
    return Optional.empty();
}
private static boolean matchesType(final String type, final TypedSPI typedSPI) {
    return typedSPI.getType().equalsIgnoreCase(type) || typedSPI.getTypeAliases().contains(type);
}

在这里,类扩展是直接在 SERVICES 中通过静态代码块注册的。

现在让我们看看 ShardingSphereServiceLoader 中的 newServiceInstances 方法。

public static <T> Collection<T> newServiceInstances(final Class<T> service) {
    if (!SERVICES.containsKey(service)) {
        return Collections.emptyList();


    }
    Collection<Object> services = SERVICES.get(service);
    if (services.isEmpty()) {
        return Collections.emptyList();
    }
    Collection<T> result = new ArrayList<>(services.size());
    for (Object each : services) {
        result.add((T) newServiceInstance(each.getClass()));
    }
    return result;
}

您可以看到,直接在通过静态代码块注册的 SERVICES 中找到接口的所有实现类返回。虽然简短,但这次漫游基本上介绍了 ShardingSphere 的 SPI 源代码。我们相信您已经注意到与 Dubbo 的 SPI 机制相比,使用 ShardingSphere 的 SPI 更加容易和简单。

总结

ShardingSphere 和 Dubbo 的 SPI 都满足按键查找指定实现类的要求,而无需每次使用时重新加载所有实现类,解决了并发加载问题。然而,与 Dubbo 相比,ShardingSphere 的 SPI 更加简洁、易用。

在编写自己的 SPI 扩展时,可以在后续参考 ShardingSphere 的实现,因为它更简单、更优雅。您可以基于 SPI 编写一个可扩展的配置文件解析器,以便了解 SPI 的功能以及其应用场景。

标签:Dubbo,Java,ShardingSphere,SPI,return,final
From: https://blog.51cto.com/JavaEdge/9105853

相关文章

  • STM32F3系列 SPI通讯缺帧问题(基于LL库)
    STM32F3系列SPI通讯缺帧问题(基于LL库)芯片型号:STM32f303RBT6开发软件:MDK5&CubeMX&VSCode现象描述主机使用SPI-DMA中断发送数据,从机接收数据总是少3个数据(16bit)。错误原因主机SPI发送完成后,片选线拉高太快,导致从机片选消失,故最后几个数据没有接收到;错误图片:解决......
  • SpringBoot 集成 Dubbo
    分布式、微服务与RPC什么是分布式?分布式就是将一个应用程序的功能拆分到多个独立的进程中,每个进程都运行在不同的机器上,通过网络连接起来,这样就形成了一个分布式的系统。什么是微服务架构?微服务架构将应用程序拆分成一组小的服务(微服务),每个服务运行在自己的进程中,服务之间通过......
  • Dubbo简介
    Dubbo是什么?Dubbo官网地址:http://dubbo.apache.orgApacheDubbo是一款易用、高性能的WEB和RPC框架,同时为构建企业级微服务提供服务发现、流量治理、可观测、认证鉴权等能力、工具与最佳实践。"Dubbo3已在阿里巴巴内部微服务集群全面落地,用于升级运行多年的HSF2框架。"什么......
  • 17 SPI驱动HC595点亮数码管
    软件版本:VIVADO2021.1操作系统:WIN1064bit硬件平台:适用XILINXA7/K7/Z7/ZU/KU系列FPGA登录米联客(MILIANKE)FPGA社区-www.uisrc.com观看免费视频课程、在线答疑解惑!1概述前面课程我们编写SPI通信FPGA的收发程序,那么这一节课,我们将展示下SPI接口的应用,使用SPI接口的74HC595......
  • 18 SPI接口ADC采集驱动设计
    软件版本:VIVADO2021.1操作系统:WIN1064bit硬件平台:适用XILINXA7/K7/Z7/ZU/KU系列FPGA登录米联客(MiLianKe)FPGA社区-www.uisrc.com观看免费视频课程、在线答疑解惑!1概述一些低速高精度的ADC/DAC都具有SPI接口,SPI的速率最高可以到几百M,另外由于接口少硬件设计简单,通信时序......
  • 15 SPI接收程序设计
    软件版本:VIVADO2021.1操作系统:WIN1064bit硬件平台:适用XILINXA7/K7/Z7/ZU/KU系列FPGA登录米联客(MILIANKE)FPGA社区-www.uisrc.com观看免费视频课程、在线答疑解惑!1概述SPI的接收器驱动程序主要为SPI_CLK和SPI_RX接收数据总线的时序来设计。通过前面的SPI协议学习,我们这里......
  • 16 SPI LOOP环路实验
    软件版本:vitis2021.1(vivado2021.1)操作系统:WIN1064bit硬件平台:适用XILINXA7/K7/Z7/ZU/KU系列FPGA登录"米联客"FPGA社区-www.uisrc.com视频课程、答疑解惑!1概述在前面完成了SPI发送驱动程序、SPI接收驱动程序设计,本文对前面的SPI收发驱动做一个环路测试,通过仿真,以及在线仿......
  • 14 SPI MASET发送程序设计
    软件版本:VIVADO2021.1操作系统:WIN1064bit硬件平台:适用XILINXA7/K7/Z7/ZU/KU系列FPGA登录米联客(MILIANKE)FPGA社区-www.uisrc.com观看免费视频课程、在线答疑解惑!1概述SPI的发送器驱动程序主要围绕SPI_MOSI以及SPI_SCLK来设计。通过前面的SPI协议学习,我们这里设计的SPI驱......
  • 13 SPI通信协议原理
    软件版本:VIVADO2021.1操作系统:WIN1064bit硬件平台:适用XILINXA7/K7/Z7/ZU/KU系列FPGA登录米联客(MILIANKE)FPGA社区-www.uisrc.com观看免费视频课程、在线答疑解惑!1概述SPI是一种串行总线接口,也是各类嵌入式设备以及FPGA应用开发中常用的一种串行通信接口。SPI的接口速度......
  • H5前端特殊艺术字体文件太大,可通过font-spider压缩
    原理:1.爬行本地html文档,分析所有css语句2.记录@font-face语句声明的字体,并且记录使用该字体的css选择器3.通过css选择器的规则查找当前html文档的节点,记录节点上的文本4.找到字体文件并删除没被使用的字符5.编码成跨平台使用的字体格式简而言之:就是爬出你项目中......