java中SPI服务提供者的接口使用总结

 更新时间:2024年10月11日 11:50:45   作者:醉卧雕龙舫 、  
SPI英文全称为Service Provider Interface,顾名思义,服务提供者接口,它是jdk提供给“服务提供厂商”或者“插件开发者”使用的接口

一:什么是SPI

SPI:“服务提供者的接口”,是一种服务发现机制

用于实现框架或库的扩展点,允许在运行时动态地插入或更换组件实现。

它提供了一个框架(JDK1.6后ServiceLoader)来发现和加载服务实现,使得软件模块能够灵活地选择和使用不同的服务提供商。

在这里插入图片描述

在java中通俗讲就是:

  • 对框架或第三方jar包提供者来说可制定规范,提供给开发者可扩展性
  • 对开发者来说可以根据需要轻松替换框架或第三方jar包中提供了SPI机制的接口的实现

在AJ-Captcha与Nacos中均提供了SPI扩展。

二:java SPI示例

1.SPI服务提供方

SPI服务提供方架构图:

在这里插入图片描述

定义接口规范:

public interface SpiService {
    /**
     * 呼叫方式
     */
    void call();
}

加载具体的服务实现:

package com.lmy.config;

import com.lmy.service.SpiService;

import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;

/**
 * @author : lmy
 * @date : 2024/9/14 上午 11:35
 * 加载具体的服务实现
 */
public class SpiServiceLoader {
    private static volatile SpiServiceLoader LOADER;

    private final SpiService spiService;

    private final List<SpiService> spiServiceList;

    /**
     * 加载服务
     * */
    private SpiServiceLoader() {
        ServiceLoader<SpiService> loader = ServiceLoader.load(SpiService.class);
        List<SpiService> list = new ArrayList<>();
        for (SpiService spiService : loader) {
            list.add(spiService);
        }
        spiServiceList = list;
        if (!list.isEmpty()) {
            // 取第一个
            spiService = list.get(0);
        } else {
            spiService = null;
        }
    }

    /**
     * SpiServiceLoader 单例加载
     * */
    public static SpiServiceLoader getLOADER() {
        if (LOADER == null) {
            synchronized (SpiServiceLoader.class) {
                if (LOADER == null) {
                    LOADER = new SpiServiceLoader();
                }
            }
        }
        return LOADER;
    }


    public void call(){
        if(spiServiceList.isEmpty()){
            System.out.println("SpiService服务未加载!");
        }else {
            SpiService spiService = spiServiceList.get(0);
            spiService.call();
        }
    }

}

默认实现:

package com.lmy.service.impl;

import com.lmy.service.SpiService;

/**
 * @author : lmy
 * @date : 2024/9/14 上午 10:58
 * 默认实现
 */
public class SpiServiceImpl implements SpiService {
    @Override
    public void call() {
        System.out.println("默认手机呼叫");
    }
}

指定服务实现方式:
须在resource下创建META-INF.services,文件名为接口全限定类名,配置为需要被加载的接口实现类的全限定类名

在这里插入图片描述

com.lmy.service.impl.SpiServiceImpl

项目打包发布本地:

在这里插入图片描述

2.SPI服务应用方开发者

开发者引入jar包使用服务:

<dependency>
    <groupId>com.lmy</groupId>
    <artifactId>SPI-interface</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
package com.lmy.Spi;

import com.lmy.config.SpiServiceLoader;
import org.junit.Test;

/**
 * @author : lmy
 * @date : 2024/9/14 上午 11:48
 */
public class SpiTest {

    @Test
    public void spiTest () {
        SpiServiceLoader loader = SpiServiceLoader.getLOADER();
        loader.call();
    }
}

执行结果:

在这里插入图片描述

开发者根据需要扩展替换为自己的服务实现:

package com.lmy.Spi.service;

import com.lmy.service.SpiService;

/**
 * @author : lmy
 * @date : 2024/9/14 下午 2:09
 */
public class SpiServiceNewImpl implements SpiService {
    @Override
    public void call() {
        System.out.println("卫星直呼");
    }
}

在这里插入图片描述

com.lmy.Spi.service.SpiServiceNewImpl

执行结果:

在这里插入图片描述

三:JavaSPI 机制的核心-ServiceLoader

上面代码可见是通过ServiceLoader 去加载具体的服务实现的

在这里插入图片描述

ServiceLoader 是从JDK1.6 开始提供的一个类,用于加载服务提供者。

进入源码可见:
其中 String PREFIX = “META-INF/services/”;
这个就是JDK的SPI功能规定的具体服务实现的配置信息文件所在的目录 META-INF/services/

在这里插入图片描述

JDK的SPI规定 服务实现者需要在 META-INF/services/ 目录下 新建文件名为 SPI接口全限定类名的文件
文件内容为 服务实现者需要被加载的具体类的全限定类名

到此这篇关于java中SPI服务提供者的接口使用总结的文章就介绍到这了,更多相关java spi详解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • intellij idea旗舰版解决学生无法注册问题详解

    intellij idea旗舰版解决学生无法注册问题详解

    这篇文章主要介绍了intellij idea旗舰版解决学生无法注册问题详解,文中通过图文示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • java使用lambda表达式多条件排序方式

    java使用lambda表达式多条件排序方式

    这篇文章主要介绍了java使用lambda表达式多条件排序方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • java中File类的构造函数及其方法

    java中File类的构造函数及其方法

    这篇文章主要介绍了java中File类的构造函数及其方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-06-06
  • java算法之二分查找法的实例详解

    java算法之二分查找法的实例详解

    这篇文章主要介绍了java算法之二分查找法的实例详解的相关资料,这里提供简单实例帮助大家学习理解这部分内容,需要的朋友可以参考下
    2017-08-08
  • Java NIO:浅析IO模型_动力节点Java学院整理

    Java NIO:浅析IO模型_动力节点Java学院整理

    在进入Java NIO编程之前,我们今天先来讨论一些比较基础的知识:I/O模型。对java io nio相关知识感兴趣的朋友一起学习吧
    2017-05-05
  • 解析java中super的用法分析

    解析java中super的用法分析

    本篇文章是对java中super的用法进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • Spring Boot整合MyBatis连接Oracle数据库的步骤全纪录

    Spring Boot整合MyBatis连接Oracle数据库的步骤全纪录

    这篇文章主要给大家介绍了关于Spring Boot整合MyBatis连接Oracle数据库的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-07-07
  • ExpressionUtil工具类的应用实例

    ExpressionUtil工具类的应用实例

    这篇文章主要给大家介绍了关于ExpressionUtil工具类的应用实例,常用的工具类有很多,这是其中一个,了解基本的API可以帮助我们更好的开发,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-04-04
  • java8 实现提取集合对象的每个属性

    java8 实现提取集合对象的每个属性

    这篇文章主要介绍了java8 实现提取集合对象的每个属性方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02
  • java原生序列化和Kryo序列化性能实例对比分析

    java原生序列化和Kryo序列化性能实例对比分析

    这篇文章主要介绍了java原生序列化和Kryo序列化性能实例对比分析,涉及Java和kryo序列化和反序列化相关实例,小编觉得很不错,这里分享给大家,希望给大家一个参考。
    2017-10-10

最新评论