当前位置:网站首页>SPI机制
SPI机制
2022-07-03 02:01:00 【xixingzhe2】
1、概念
spi全称为 (Service Provider Interface),是JDK内置的一种服务提供发现机制。SPI是一种动态替换发现的机制,一种解耦非常优秀的思想。它是jdk提供给“服务提供厂商”或者“插件开发者”使用的接口,是一种扩展机制。
2、用途
在面向对象的设计中,模块之间我们一般会采取面向接口编程的方式,而在实际编程过程过程中,API的实现是封装在jar中,当我们想要换一种实现方法时,还要生成新的jar替换以前的实现类。而通过jdk的SPI机制就可以实现,首先不需要修改原来作为接口的jar的情况下,将原来实现的那个jar替换为另外一种实现的jar即可。
总结一下SPI的思想:在系统的各个模块中,往往有不同的实现方案,例如日志模块的方案、xml解析的方案等,为了在装载模块的时候不具体指明实现类,我们需要一种服务发现机制,java spi就提供这样一种机制。有点类似于IoC的思想,将服务装配的控制权移到程序之外,在模块化设计时尤其重要。
示例:重写第三方jar中SPRING BEAN的方式_xixingzhe2的博客-CSDN博客
3、优缺点
3.1 优点
- 为了解耦,将接口和具体实现分离开来。
- 提高框架的扩展性。应用程序可以根据实际业务情况启用框架扩展或替换框架组件,避免接口和实现都写在一起,调用方无权选择使用具体的实现类。
3.2 缺点
- 虽然ServiceLoader也算是使用的延迟加载,但是基本只能通过遍历全部获取,也就是接口的实现类全部加载并实例化一遍。如果你并不想用某些实现类,它也被加载并实例化了,这就造成了浪费。获取某个实现类的方式不够灵活,只能通过Iterator形式获取,不能根据某个参数来获取对应的实现类。
- 多个并发多线程使用ServiceLoader类的实例是不安全的。
4、规范
定义服务的通用接口,针对通用的服务接口,提供具体的实现类。
- 在jar包(服务提供者)的META-INF/services/目录中,新建一个文件,文件名为SPI接口的"全限定名"(如:com.ybw.spi.service.DemoService)。 文件内容为该接口的具体实现类的"全限定名"(如:com.ybw.spi.service.impl.DemoOneServiceImpl)。
- 将spi所在jar放在主程序的classpath中。
- 服务调用方使用java.util.ServiceLoader去动态加载具体的实现类到JVM中。
5、SPI示例
代码结构
模块依赖关系
5.1 spi-service
定义接口
package com.ybw.spi.service;
/**
* Demo service. Implements should be use SPI.
*
* @author ybw
* @version V1.0
* @className DemoService
* @date 2022/6/29
**/
public interface DemoService {
String sayHello();
}
5.2 spi-service-impl-one
实现一
package com.ybw.spi.service.impl;
import com.ybw.spi.service.DemoService;
/**
* Implement for DemoService
*
* @author ybw
* @version V1.0
* @className DemoOneServiceImpl
* @date 2022/6/29
**/
public class DemoOneServiceImpl implements DemoService {
@Override
public String sayHello() {
return "hello world one";
}
}
META-INF/services/下创建文件com.ybw.spi.service.DemoService,内容为
com.ybw.spi.service.impl.DemoOneServiceImpl
5.3 spi-service-impl-two
实现二
package com.ybw.spi.service.impl;
import com.ybw.spi.service.DemoService;
/**
* Implement for DemoService
*
* @author ybw
* @version V1.0
* @className DemoOneServiceImpl
* @date 2022/6/29
**/
public class DemoTwoServiceImpl implements DemoService {
@Override
public String sayHello() {
return "hello world two";
}
}
META-INF/services/下创建文件com.ybw.spi.service.DemoService,内容为
com.ybw.spi.service.impl.DemoTwoServiceImpl
5.4 spi-execute
执行模块
package com.ybw.spi.test;
import com.ybw.spi.service.DemoService;
import com.ybw.spi.service.impl.DemoOneServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import java.util.ServiceLoader;
/**
* 加载使用
*
* @author ybw
* @version V1.0
* @className SpiTest
* @date 2022/6/29
**/
@Slf4j
public class SpiTest {
/**
* @methodName: spiTest
* @return: void
* @author: ybw
* @date: 2022/6/29
**/
@Test
public void spiTest() {
ServiceLoader<DemoService> demoServices = ServiceLoader.load(DemoService.class);
demoServices.forEach(demoService -> {
log.info(demoService.getClass().getName());
log.info("ClassLoader:{}",demoService.getClass().getClassLoader());
log.info(demoService.sayHello());
});
}
}
引入依赖spi-service-impl-one
输入日志
[INFO ] 2022-06-29 16:12:58.135 [main] com.ybw.spi.test.SpiTest - com.ybw.spi.service.impl.DemoOneServiceImpl
[INFO ] 2022-06-29 16:12:58.146 [main] com.ybw.spi.test.SpiTest - ClassLoader:[email protected]
[INFO ] 2022-06-29 16:12:58.151 [main] com.ybw.spi.test.SpiTest - hello world one
引入的实现模块不同,打印的日志也会不同。
5.5 代码地址
https://gitee.com/xixingzhe2/share/tree/master/spi/spi-jdk-demo
6、spring spi
在springboot的自动装配过程中,最终会加载META-INF/spring.factories文件,而加载的过程是由SpringFactoriesLoader加载的。
从CLASSPATH下的每个Jar包中搜寻所有META-INF/spring.factories配置文件,然后将解析properties文件,找到指定名称的配置后返回。注意的是,其实这里不仅仅是会去ClassPath路径下查找,会扫描所有路径下的Jar包,只不过这个文件只会在Classpath下的jar包中。
可以看另一边文章:spring boot 自定义starter_xixingzhe2的博客-CSDN博客
源代码:https://gitee.com/xixingzhe2/share/tree/master/spring/spring-demo-starter-parent
7、jdk与spring spi区别
jdk | spring | |
加载类不同 | JDK使用的工具类是ServiceLoader | Spring中使用的类是SpringFactoriesLoader,在 org.springframework.core.io.support包中 |
文件路径不同 | jdk配置放在META-INF/services/目录中 | spring配置放在 META-INF/spring.factories中 |
边栏推荐
- Query product cases - page rendering data
- Redis: simple use of redis
- Network security - talking about security threats
- Hard core observation 547 large neural network may be beginning to become aware?
- 机器学习流程与方法
- 8 free, HD, copyright free video material download websites are recommended
- 【Camera专题】手把手撸一份驱动 到 点亮Camera
- ByteDance data Lake integration practice based on Hudi
- Trial setup and use of idea GoLand development tool
- stm32F407-------IIC通讯协议
猜你喜欢
Learn BeanShell before you dare to say you know JMeter
Stm32f407 ------- IIC communication protocol
[camera topic] complete analysis of camera dtsi
ByteDance data Lake integration practice based on Hudi
Ni visa fails after LabVIEW installs the third-party visa software
PyTorch 卷积网络正则化 DropBlock
詳細些介紹如何通過MQTT協議和華為雲物聯網進行通信
全链路数字化转型下,零售企业如何打开第二增长曲线
MySQL学习03
Processing of tree structure data
随机推荐
小程序开发黑马购物商城中遇到的问题
苏世民:25条工作和生活原则
Y54. Chapter III kubernetes from introduction to mastery -- ingress (27)
Ni visa fails after LabVIEW installs the third-party visa software
LabVIEW安装第三方VISA软件后NI VISA失效
PS remove watermark details
udp接收队列以及多次初始化的测试
What are the differences between software testers with a monthly salary of 7K and 25K? Leaders look up to you when they master it
8 free, HD, copyright free video material download websites are recommended
Modify table structure
CFdiv2-Fixed Point Guessing-(区间答案二分)
Comment le chef de file gère - t - il l'équipe en cas d'épidémie? Contributions communautaires
stm32F407-------DMA
Reprint some Qt development experience written by great Xia 6.5
Network security - scan
Custom components, using NPM packages, global data sharing, subcontracting
Leetcode (540) -- a single element in an ordered array
Trial setup and use of idea GoLand development tool
微信小程序开发工具 POST net::ERR_PROXY_CONNECTION_FAILED 代理问题
502 (bad gateway) causes and Solutions