SPI技术实现对比Java SPI、Spring SPI、Dubbo SPI

概念

SPI机制,全称为Service Provider Interface,是一种服务提供发现机制。

SPI的核心思想是面向接口编程,它允许程序员定义接口,并由第三方实现这些接口。在运行时,SPI机制能够发现并加载所有可用的实现,然后根据需要实例化和使用它们。这种方式提供了一种灵活的方式来扩展应用程序或框架的功能,而不需要修改原有的代码。

以下是SPI机制的一些关键点:

  • 服务提供者接口:SPI定义了一个接口,服务提供者需要实现这个接口以提供服务。例如,Java中的java.sql.Driver接口就是一个典型的SPI接口。

  • 实现类注册:服务提供者需要提供一个实现类,并在类上使用特定的注解(如@ServiceProvider)来标记这个类是一个SPI实现。

  • 配置文件:在类路径下的指定目录中,服务提供者还需要创建一个以接口全名命名的文件,文件内容是实现类的全名,这样JVM就能在启动时找到并加载这些实现类。

  • 服务发现:当应用程序需要使用某个服务时,SPI机制会扫描指定目录下的配置文件,找到所有的实现类,并通过反射实例化它们,然后根据预设的规则选择一个实现来使用。

  • 应用场景:SPI机制常用于框架开发中,允许用户或第三方插件提供具体的实现,从而扩展框架的功能。例如,日志框架Slf4j就是通过SPI机制来绑定不同的日志实现。

Java SPI

示例

    1. 定义ApiService接口
package com.example.spidemo.javaspi;

/**
 * @author wdz
 * @date 2024/2/26
 */
public interface ApiService {
    public void test();
}

    1. 定义两个接口实现类
package com.example.spidemo.javaspi;

/**
 * @author wdz
 * @date 2024/2/26
 */
public class OneApiService implements ApiService{
    @Override
    public void test() {
        System.out.println("OneApiService");
    }
}

package com.example.spidemo.javaspi;

/**
 * @author wdz
 * @date 2024/2/26
 */
public class TwoApiService implements ApiService{
    @Override
    public void test() {
        System.out.println("TwoApiService");
    }
}

    1. META-INF/services下创建全限定名的文件
      在这里插入图片描述
      文件中内容为:
com.example.spidemo.javaspi.OneApiService
com.example.spidemo.javaspi.TwoApiService
    1. 使用ServiceLoader调用实现类
package com.example.spidemo.javaspi;

import java.util.ServiceLoader;

/**
 * @author wdz
 * @date 2024/2/26
 */
public class ApiMain {
    public static void main(String[] args) {
        ServiceLoader<ApiService> services = ServiceLoader.load(ApiService.class);
        services.forEach(ApiService::test);
    }
}

特点

Java SPI的特点包括服务发现机制、解耦和灵活性、易于扩展、延迟加载、易于替换组件以及内置于JDK。

优点:

  • 面向接口编程:SPI机制允许开发者面向接口编程,而不是具体的实现,这样可以在不修改原有代码的情况下引入新的实现类。

  • 实现解耦:通过SPI机制,第三方服务模块的装配控制逻辑与调用者的业务代码分离,有助于降低模块间的耦合度。

  • 动态加载实现:应用程序可以根据实际业务需求动态地加载和使用不同的服务实现,提高了应用程序的灵活性。
    框架扩展:SPI机制特别适合用于框架开发,因为它允许用户或第三方为框架提供具体的实现,从而扩展框架的功能。

  • 提高启动速度:由于支持延迟加载,只有在真正需要使用某个服务时,相关的实现类才会被加载和实例化,这有助于提高应用程序的启动速度。

缺点:

  • 不能按需加载:尽管ServiceLoader实现了延迟加载,但是它基本上只能通过遍历全部获取,这意味着不能精确地按需加载特定的实现。

  • 配置复杂性:使用SPI机制需要在META-INF/services目录下创建配置文件,并且需要手动添加实现类的全名,这增加了配置的复杂性。

  • 版本管理:当存在多个版本的同一服务实现时,可能会导致版本冲突的问题,管理起来较为困难。

  • 性能考虑:在大量实现类的情况下,SPI的遍历加载可能会导致性能问题。

Spring SPI

示例

    1. 定义ApiService接口
package com.example.spidemo.springspi;

/**
 * @author wdz
 * @date 2024/2/26
 */
public interface ApiService {
    public void test();
}

    1. 定义两个接口实现类
package com.example.spidemo.springspi;

/**
 * @author wdz
 * @date 2024/2/26
 */
public class OneApiService implements ApiService{
    @Override
    public void test() {
        System.out.println("OneApiService");
    }
}

package com.example.spidemo.springspi;

/**
 * @author wdz
 * @date 2024/2/26
 */
public class TwoApiService implements ApiService{
    @Override
    public void test() {
        System.out.println("TwoApiService");
    }
}

    1. META-INF下创建spring.factories
      文件中内容为:
com.example.spidemo.springspi.ApiService=\
com.example.spidemo.springspi.OneApiService,\
com.example.spidemo.springspi.TwoApiService
    1. 使用SpringFactoriesLoader调用实现类
package com.example.spidemo;

import com.example.spidemo.springspi.ApiService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.support.SpringFactoriesLoader;

import java.util.List;

@SpringBootTest
class SpiDemoApplicationTests {

    @Test
    void contextLoads() {

        List<ApiService> apiServices = SpringFactoriesLoader.loadFactories(ApiService.class, Thread.currentThread().getContextClassLoader());
        apiServices.forEach(ApiService::test);
    }

}

特点

Spring SPI机制非常类似,但还是有一些差异。

    1. Java SPI是一个服务提供接口对应一个配置文件,配置文件中存放当前接口的所有实现类,多个服务提供接口对应多个配置文件,所有配置都在services目录下。
    1. Spring SPI是一个spring.factories 配置文件存放多个接口及对应的实现类,以接口全限定名作为key,实现类作为value来配置,多个实现类用逗号隔开,'spring.factories’一个配置文件。
    1. 和Java SPI一样,Spring SPI也无法获取某个固定的实现,只能按顺序获取所有实现。

Dubbo SPI

示例

    1. 定义ApiService接口,接口需要使用@SPI
package com.example.spidemo.dubbospi;

import org.apache.dubbo.common.extension.ExtensionScope;
import org.apache.dubbo.common.extension.SPI;

/**
 * @author wdz
 * @date 2024/2/26
 */
@SPI(
        scope = ExtensionScope.MODULE
)
public interface ApiService {
    public void test();
}

    1. 定义两个接口实现类
package com.example.spidemo.dubbospi;

/**
 * @author wdz
 * @date 2024/2/26
 */
public class OneApiService implements ApiService{
    @Override
    public void test() {
        System.out.println("OneApiService");
    }
}

package com.example.spidemo.dubbospi;

/**
 * @author wdz
 * @date 2024/2/26
 */
public class TwoApiService implements ApiService{
    @Override
    public void test() {
        System.out.println("TwoApiService");
    }
}

    1. META-INF/dubbospi目录下创建全限定名文件:
      在这里插入图片描述

文件中内容为:

oneApiService=com.example.spidemo.dubbospi.OneApiService
twoApiService=com.example.spidemo.dubbospi.TwoApiService
    1. 使用ExtensionLoader调用实现类

    @Test
    void dubboLoads(){
        ExtensionLoader<ApiService> extensionLoader = ExtensionLoader.getExtensionLoader(ApiService.class);
        ApiService oneApiService = extensionLoader.getExtension("oneApiService");
        oneApiService.test();
        ApiService twoApiService = extensionLoader.getExtension("twoApiService");
        twoApiService.test();
        
    }

特点

Dubbo SPI的特点包括丰富的扩展点、灵活的配置以及与Dubbo框架的紧密集成,而其优点主要是易于扩展和维护,缺点则是学习成本相对较高且实现较为复杂。

Dubbo SPI的特点具体如下:

  • 丰富的扩展点:Dubbo 提供了众多的扩展点,允许用户根据需求适配不同的实现,这使得Dubbo非常灵活,可以根据不同的场景进行定制和扩展。

  • 灵活的配置:用户可以通过配置文件轻松地增加新的接口实现,无需修改现有代码,这大大简化了维护工作并提高了系统的可维护性。

  • 与Dubbo框架紧密集成:Dubbo SPI 专为 Dubbo 框架设计,与框架的其他部分紧密集成,提供了更多的灵活性和高级扩展功能。

Dubbo SPI的优点包括:

  • 易于扩展:开发者可以通过实现新的接口来扩展服务,而不需要修改原有的服务代码,这大大提高了系统的可维护性和可扩展性。

  • 维护简单:由于Dubbo SPI允许通过配置文件来添加新的服务实现,因此可以不停机更新服务实现,便于持续集成和快速迭代。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/412061.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

文献速递:深度学习--深度学习方法用于帕金森病的脑电图诊断

文献速递&#xff1a;深度学习–深度学习方法用于帕金森病的脑电图诊断 01 文献速递介绍 人类大脑在出生时含有最多的神经细胞&#xff0c;也称为神经元。这些神经细胞无法像我们身体的其他细胞那样自我修复。随着年龄的增长&#xff0c;神经元逐渐死亡&#xff0c;因此变得…

docker小知识:linux环境安装docker

安装必要软件包&#xff0c;执行如下命令 yum install -y yum-utils device-mapper-persistent-data lvm2目的是确保在安装 Docker 之前&#xff0c;系统已经安装了必要的软件包和服务&#xff0c;以支持 Docker 的正常运行。设置yum源&#xff0c;添加Docker官方的CentOS存储…

Open CASCADE学习|GC_MakeArcOfCircle构造圆弧

目录 1、通过圆及圆的两个参数创建圆弧&#xff0c;参数为弧度角 2、通过圆及圆上的一点、圆的1个参数创建圆弧&#xff0c;参数为弧度角&#xff0c;Sense决定方向 3、通过圆及圆上的两个点创建圆弧&#xff0c;Sense决定方向 4、通过三点创建圆弧&#xff0c;最后一点应安…

Mysql 常用数据类型

数值型(整数)的基本使用 如何定义一个无符号的整数 数值型(bit)的使用 数值型(小数)的基本使用 字符串的基本使用 字符串使用细节 日期类型的基本使用

用html编写的小广告板

用html编写的小广告板 相关代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</tit…

【练习——打印每一位数】

打印一个数的每一位 举个例子&#xff1a;我们现在要求打印出123的每一位数字。我们需要去想123%10等于3&#xff0c;就可以把3单独打印出来了&#xff0c;然后再将123/10可以得到12&#xff0c;将12%10就可以打印出2&#xff0c;而我们最后想打印出1&#xff0c;只需要1%10就…

国内大型语言模型(LLM)的研发及突破性应用

随着人工智能技术的迅猛发展&#xff0c;大型语言模型&#xff08;LLM&#xff09;在国内外科技领域成为了热点话题。这些模型因其在文本生成、理解和处理方面的卓越能力&#xff0c;被广泛应用于各种行业和场景中。 在中国&#xff0c;一批人工智能公司在LLM的研发与应用方面…

科技云报道:黑马Groq单挑英伟达,AI芯片要变天?

科技云报道原创。 近一周来&#xff0c;大模型领域重磅产品接连推出&#xff1a;OpenAI发布“文字生视频”大模型Sora&#xff1b;Meta发布视频预测大模型 V-JEPA&#xff1b;谷歌发布大模型 Gemini 1.5 Pro&#xff0c;更毫无预兆地发布了开源模型Gemma… 难怪网友们感叹&am…

数据结构之栈的链表实现

数据结构之栈的链表实现 代码&#xff1a; #include<stdio.h> #include<stdbool.h> #include<stdlib.h> //链表节点定义 typedef struct node {int value;struct node* next; }Node; //入栈操作 bool push(Node** head, int val) {if (*head NULL){*head …

如何学习Arduino单片机

&#xff08;本文为简单介绍&#xff0c;内容源于网络&#xff09; 学习Arduino相关的网址和开源社区&#xff1a; Arduino官方文档: Arduino - HomeArduino Forum: Arduino ForumArduino Playground: Arduino Playground - HomePageGitHub: GitHub: Let’s build from here …

第十三天-mysql交互

目录 1.安装MySQL connector 方式1&#xff1a;直接安装 方式2&#xff1a;下载 2.创建链接 3.游标Cursor 4.事务控制 5. 数据库连接池 1. 使用 6.循环执行SQL语句 不了解mysql的可以先了解mysql基础 1.安装MySQL connector 1. MySQL connector 是MySQL官方驱动模块…

接口测试 —— Jmeter读取数据库数据作测试参数

1、添加Jdbc Request 2、添加ForEach控制器(右键线程组->逻辑控制器->ForEach控制器) ①输入变量的前缀&#xff1a;mobilephone&#xff1b; 从jdbc request设置的变量得知&#xff0c;我们要取的值为mobilephone_1、mobilephone_2、mobilephone_3......所以这里输入m…

备战蓝桥杯---DFS基础刷题

话不多说&#xff0c;直接看题&#xff1a; 1.注意搜索顺序枚举方式 首先&#xff0c;看到数据范围&#xff0c;我们就不可以直接每一轮3次的暴力。 我们可以发现a^2的大部分情况>2a以及a1,并且&#xff0c;我们发现其实1的操作是没有必要的&#xff08;因为2a以经包括了&…

Spring-Cloud-Gateway集成Sentinel限流

1&#xff09;gateway添加sentinel相关依赖 <spring-cloud.version>2021.0.1</spring-cloud.version> <spring-cloud-alibaba.version>2021.0.1.0</spring-cloud-alibaba.version><dependencies><!--gateway--><dependency><gro…

【c语言】if 选择语句

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;C语言 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进步&…

Python爬虫实战:从API获取数据

引言 在现代软件开发中&#xff0c;API已经成为获取数据的主要方式之一。API允许不同的软件应用程序相互通信&#xff0c;共享数据和功能。在本文中&#xff0c;我们将学习如何使用Python从API获取数据&#xff0c;并探讨其在实际应用中的价值。 目录 引言 二、API基础知识 …

数据湖delta lake

Table of Content1. 课程2. 前置技能3. 一、数据湖概念[了解] 3.1. 1.1 企业的数据困扰 3.1.1. 困扰一&#xff1a;互联网的兴起和数据孤岛3.1.2. 困扰二&#xff1a;非结构化数据3.1.3. 困扰三&#xff1a;保留原始数据3.1.4. 补充&#xff1a;什么是结构化&#xff1f; 3.1.4…

【Git教程】(三)提交详解 —— add、commit、status、stach命令的说明,提交散列值与历史,多次提交及忽略 ~

Git教程 提交详解 1️⃣ 访问权限与时间戳2️⃣ add命令与 commit 命令3️⃣ 提交散列值4️⃣ 提交历史5️⃣ 一种特别的提交查看方法6️⃣ 同一项目的多部不同历史6.1 部分输出&#xff1a;-n6.2 格式化输出&#xff1a;--format、--oneline6.3 统计修改信息&#xff1a;--st…

rtthread stm32h743的使用(一)新工程建立

我们要在rtthread studio 开发环境中建立stm32h743xih6芯片的工程。我们使用一块stm32h743及fpga的核心板完成相关实验&#xff0c;核心板如图&#xff1a; 1.打开rtthread studio填写芯片型号及调试口&#xff0c;我们的调试串口为USART1_PA9,PA10。 2.编译新工程并且下载 …

pycharm如何安装pygame库

pycharm如何安装pygame库 PyCharm是Python中广受欢迎的一种IDE&#xff0c;它可以为用户提供许多工具和便利的服务&#xff0c;从而大大提高开发效率。pygame库可以用python进行游戏开发提供很好的支持&#xff0c;那么在ptcharm中如何安装pygame库呢&#xff1f; 一、安装步…