概述
前言:
SPI(Service Provider Interface),是JDK内置的一种服务提供发现机制,Java中 SPI 机制主要思想是将装配的控制权移到程序之外,在模块化设计中这个机制尤其重要,其核心思想就是解耦
1、大家都知道API,却不太了解SPI
2、API是开发人员设定好的接口和实现功能供别人调用
3、SPI是制定接口规范,供其他服务提供模块来按照此接口自定义实现业务的权力
一、Java标准 SPI 的构成三大组件
1、Service 是一个公开的接口或抽象类,定义了一个抽象的功能方法函数
2、Service Provider:是 Service 接口的一个实现类
3、ServiceLoader:SPI机制中的核心组件,负责运行时发现并加载 Service Provider
二、Java SPI 的三大要素
1、文件位置路径:必须在JAR包(项目模块)中 /resources/META-INF/services/ 目录下
2、文件名称:Service接口或抽象类的全限定名
3、文件内容:Service接口或抽象类的实现类的全限定名。如果有多个实现类,那么每一个类在文件中单独占一行
使用:
1、在提供接口模块中定义一个标准接口或抽象类
package com.hkl.mpjoin.modules.finance.spi.service;
/**
* <p>Description:人接口类-学习SPI机制-对外部提供的标准接口</p>
* <p>Author:hkl</p>
* <p>Date:2022/11/28</p>
*/
public interface PeopleSPIService {
String peopleSpeak();
}
2、在提供接口模块中定义一个此接口的默认实现类
package com.hkl.mpjoin.modules.finance.spi.service.impl;
import com.hkl.mpjoin.modules.finance.spi.service.PeopleSPIService;
/**
* <p>Description:中国人实现类-SPI机制默认实现类</p>
* <p>Author:hkl</p>
* <p>Date:2022/11/28</p>
*/
public class ChinesePeople implements PeopleSPIService {
@Override
public String peopleSpeak() {
return "中国人说汉语!";
}
}
3、在提供接口模块中的 classpath:resourcesMETA-INFservices 目录下,创建上面接口全限定名称的文件,文件内容就是上面全限定实现类的路径及名称
com.hkl.mpjoin.modules.finance.spi.service.impl.ChinesePeople
4、在提供实现类模块中引入提供接口模块的依赖坐标,然后同样操作 第3步 ,创建接口全限定名称的文件,这里的文件内容就是此模块中全限定实现类的路径及名称
com.hkl.rmqp.modules.spi.service.impl.AmericanPeople
com.hkl.rmqp.modules.spi.service.impl.JapanesePeople
AmericanPeople 实现类:
package com.hkl.rmqp.modules.spi.service.impl;
import com.hkl.mpjoin.modules.finance.spi.service.PeopleSPIService;
/**
* <p>Description:美国人实现类-测试SPI</p>
* <p>Author:hkl</p>
* <p>Date:2022/11/28</p>
*/
public class AmericanPeople implements PeopleSPIService {
@Override
public String peopleSpeak() {
return "美国人说英语!";
}
}
JapanesePeople 实现类:
package com.hkl.rmqp.modules.spi.service.impl;
import com.hkl.mpjoin.modules.finance.spi.service.PeopleSPIService;
/**
* <p>Description:日本人实现类-测试SPI</p>
* <p>Author:hkl</p>
* <p>Date:2022/11/28</p>
*/
public class JapanesePeople implements PeopleSPIService {
@Override
public String peopleSpeak() {
return "日本人说日语!";
}
}
5、测试加载实现类方法
//测试 Java SPI 机制 start
ServiceLoader<PeopleSPIService> loads = ServiceLoader.load(PeopleSPIService.class);
loads.forEach(loadObj -> {
System.out.println("测试SPI结果为:" + loadObj.peopleSpeak());
});
//测试 Java SPI 机制 end
成功全部输出实现类结果:
小结:
【1】当服务的提供者提供了一种接口的实现之后,需要在 classpath下的 /META-INF/services/ 目录里创建一个以服务接口命名的文件,这个文件里的内容就是这个接口的具体的实现类
【2】当其他的程序需要这个服务的时候,就可以通过查找这个jar包(一般都是以jar包做依赖)的 /resources/META-INF/services 中的配置文件,配置文件中有接口的具体实现类名,可以根据这个类名进行加载实例化,就可以使用该服务了
【3】为某个 jar 依赖提供服务,我们工程继承这个依赖并提供服务,而其他使用者使用我们的工程依赖的时候,就可以在使用原 jar 依赖的功能的同时使用我们为 jar 提供的服务实现
【4】JDK中查找提供服务实现的工具类是:java.util.ServiceLoader
这就是 Java SPI 机制,简单来说就是接口方为实现功能,但又不确定使用者使用哪个厂商或供应商的产品,所以把标准接口开放出来,让使用者按照自己的需求去实现
一段话助力彻底理解 Java SPI 机制
一句话理解:SPI 是当我们身为框架开发者时候,在你无法形成绝对权力、强制使用者去使用的的时候,"放权" 往往是比较明智的选择,适当让使用者去自定义实现
例子:公司让你写一个对象存储的服务组件,然后下放给其他业务部门使用。你努努力,实现了阿里云OSS,腾讯COS、华为对象存储等实现,供业务部门使用。这时候A部门跳出来说,他们用的七牛的kodo;B部门说,他们用的HDFS,这时候你咋办?你接着自己去增加这些实现吗?不现实,量太大了。这时候,最好的方式就是,提供一个口子,供使用者按自己的需求,自己去实现这个时候SPI就发挥作用了。
SPI的功能以及使用方式,可以支持公司部门内部,引入你的组件后,在不用更改你组件源码的前提下,面向SPI接口,在他们自己的业务项目内部去自己增加实现。问题完美解决
总结:
1、Java SPI机制,基于面向接口编程,优雅的实现模块之间的解耦
最后
以上就是兴奋黄豆为你收集整理的Java SPI机制的使用和理解的全部内容,希望文章能够帮你解决Java SPI机制的使用和理解所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复