java中SPI服务提供者的接口使用总结
作者:醉卧雕龙舫 、
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详解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!