• 你知道SPI的原理以及实现?


    1、什么是SPI

    SPI(Service Provider Interface),是JDK内置的一种服务提供发现机制,可以用来启用框架扩展和替换组件,主要是被框架的开发人员使用,比如 java.sql.Driver 接口,其他不同厂商可以针对同一接口做出不同的实现,MySQL 和 PostgreSQL 都有不同的实现提供给用户,而Java的SPI机制可以为某个接口寻找服务实现。Java中SPI机制主要思想是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要,其核心思想就是解耦
    Java SPI 实际上是“基于接口的编程+策略模式+配置文件”组合实现的动态加载机制。
    SPI与API区别:

    • API是调用并用于实现目标的类、接口、方法等的描述;
    • SPI是扩展和实现以实现目标的类、接口、方法等的描述;

    换句话说,API 为操作提供特定的类、方法,SPI 通过操作来符合特定的类、方法。
    当服务的提供者提供了一种接口的实现之后,需要在classpath下的META-INF/services/目录里创建一个以服务接口命名的文件,这个文件里的内容就是这个接口的具体的实现类。当其他的程序需要这个服务的时候,就可以通过查找这个jar包(一般都是以jar包做依赖)的META-INF/services/中的配置文件,配置文件中有接口的具体实现类名,可以根据这个类名进行加载实例化,就可以使用该服务了。JDK中查找服务的实现的工具类是:java.util.ServiceLoader。
    面向的对象的设计里,我们一般推荐模块之间基于接口编程,模块之间不对实现类进行硬编码。一旦代码里涉及具体的实现类,就违反了可拔插的原则,如果需要替换一种实现,就需要修改代码。
    为了实现在模块装配的时候不用在程序里动态指明,这就需要一种服务发现机制。java spi就是提供这样的一个机制:为某个接口寻找服务实现的机制。这有点类似IOC的思想,将装配的控制权移到了程序之外。

    2、使用场景

    概括地说,适用于:调用者根据实际使用需要,启用、扩展、或者替换框架的实现策略
    比较常见的例子:

    • 数据库驱动加载接口实现类的加载 => JDBC加载不同类型数据库的驱动
    • 日志门面接口实现类加载 => SLF4J加载不同提供商的日志实现类
    • Spring => Spring中大量使用了SPI,比如:对servlet3.0规范对ServletContainerInitializer的实现、自动类型转换Type Conversion SPI(Converter SPI、Formatter SPI)等
    • Dubbo => Dubbo中也大量使用SPI的方式实现框架的扩展, 不过它对Java提供的原生SPI做了封装,允许用户扩展实现Filter接口

    3、SPI的优缺点

    优点

    使用Java SPI机制的优势是实现解耦,使得第三方服务模块的装配控制的逻辑与调用者的业务代码分离,而不是耦合在一起。应用程序可以根据实际业务情况启用框架扩展或替换框架组件
    相比使用提供接口jar包,供第三方服务模块实现接口的方式,SPI的方式使得源框架,不必关心接口的实现类的路径,可以不用通过下面的方式获取接口实现类:

    • 代码硬编码import 导入实现类
    • 指定类全路径反射获取:例如在JDBC4.0之前,JDBC中获取数据库驱动类需要通过Class.forName(“com.mysql.jdbc.Driver”),类似语句先动态加载数据库相关的驱动,然后再进行获取连接等的操作
    • 第三方服务模块把接口实现类实例注册到指定地方,源框架从该处访问实例

    通过SPI的方式,第三方服务模块实现接口后,在第三方的项目代码的META-INF/services目录下的配置文件指定实现类的全路径名,源码框架即可找到实现类

    缺点

    • 虽然ServiceLoader也算是使用的延迟加载,但是基本只能通过遍历全部获取,也就是接口的实现类全部加载并实例化一遍。如果你并不想用某些实现类,它也被加载并实例化了,这就造成了浪费。获取某个实现类的方式不够灵活,只能通过Iterator形式获取,不能根据某个参数来获取对应的实现类。
    • 多个并发多线程使用ServiceLoader类的实例是不安全的。
  • 相关阅读:
    Android ViewPager2 + Fragment + BottomNavigationView 联动
    兆德心理平台系统模式开发介绍
    css知识学习系列(3)-每天10个知识点
    Xcode预览(Preview)显示List视图内容的一个Bug及解决
    【python】基础语法
    【Vue】用Vue代码详细介绍computed计算属性的用法
    搭建Javaweb图书管理系统---遇到问题总结(持续更新~~~)
    qt笔记之qml和C++的交互系列(一):初记
    【Linux网络】搭建内外网的网关服务器,实现DNS分离解析与DHCP自动分配
    如何避免 SSL 中断并续订证书
  • 原文地址:https://blog.csdn.net/weixin_50999696/article/details/139388871