java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java spi详解

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

作者:醉卧雕龙舫 、

SPI英文全称为Service Provider Interface,顾名思义,服务提供者接口,它是jdk提供给“服务提供厂商”或者“插件开发者”使用的接口

一:什么是SPI

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

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

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

在这里插入图片描述

在java中通俗讲就是:

在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详解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文