当前位置:网站首页>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.DemoOneServiceImpl5.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.DemoTwoServiceImpl5.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中 |
边栏推荐
- What are the key points often asked in the redis interview
- DDL basic operation
- 2022 financial product revenue ranking
- Huakaiyun | virtual host: IP, subnet mask, gateway, default gateway
- 技术大佬准备就绪,话题C位由你决定
- Hard core observation 547 large neural network may be beginning to become aware?
- Swift development learning
- Use go language to realize try{}catch{}finally
- Leetcode (540) -- a single element in an ordered array
- Analyzing several common string library functions in C language
猜你喜欢

Distributed transaction solution
![[shutter] top navigation bar implementation (scaffold | defaulttabcontroller | tabbar | tab | tabbarview)](/img/f1/b17631639cb4f0f58007b86476bcc2.gif)
[shutter] top navigation bar implementation (scaffold | defaulttabcontroller | tabbar | tab | tabbarview)

What are the key points often asked in the redis interview

Custom components, using NPM packages, global data sharing, subcontracting

微服务组件Sentinel (Hystrix)详细分析

stm32F407-------DMA
![[shutter] hero animation (hero realizes radial animation | hero component createrecttween setting)](/img/e7/915404743d6639ac359bb4e7f7fbb7.jpg)
[shutter] hero animation (hero realizes radial animation | hero component createrecttween setting)

《上市风云》荐书——唯勇气最可贵

How to deal with cache hot key in redis

Visualisation de l'ensemble de données au format yolov5 (fichier labelme json)
随机推荐
树形结构数据的处理
Exception handling in kotlin process
Socket programming
easyExcel
Anna: Beibei, can you draw?
Network security - talking about security threats
可视化yolov5格式数据集(labelme json文件)
《上市风云》荐书——唯勇气最可贵
[shutter] shutter debugging (debugging fallback function | debug method of viewing variables in debugging | console information)
【Camera专题】HAL层-addChannel和startChannel简析
The testing process that software testers should know
DDL basic operation
去除网页滚动条方法以及内外边距
【Camera专题】手把手撸一份驱动 到 点亮Camera
What are the differences between software testers with a monthly salary of 7K and 25K? Leaders look up to you when they master it
Redis:Redis的简单使用
PS remove watermark details
How can retail enterprises open the second growth curve under the full link digital transformation
stm32F407-------ADC
Leetcode(540)——有序数组中的单一元素