欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 时评 > java中SPI(服务提供者的接口)

java中SPI(服务提供者的接口)

2024/10/25 1:32:27 来源:https://blog.csdn.net/qq_41863697/article/details/142257911  浏览:    关键词:java中SPI(服务提供者的接口)

java中SPI(服务提供者的接口)

    • 一:什么是SPI
    • 二:java SPI示例
      • 1.SPI服务提供方
      • 2.SPI服务应用方开发者
    • 三:JavaSPI 机制的核心-ServiceLoader

一:什么是SPI

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

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

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

在这里插入图片描述

在java中通俗讲就是:

  • 对框架或第三方jar包提供者来说可制定规范,提供给开发者可扩展性
  • 对开发者来说可以根据需要轻松替换框架或第三方jar包中提供了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 {@Overridepublic 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 {@Testpublic 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 {@Overridepublic 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接口全限定类名的文件
文件内容为 服务实现者需要被加载的具体类的全限定类名

具体源码底层实现参考:https://blog.csdn.net/qq_37883866/article/details/139000021 中第3点

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com